springmvc上传图片后显示损毁或不能显示_来喽 ! SpringMVC框架第二篇

 种一棵树最好的时间是十年前,其次就是现在!

学习SpringMVC第二篇

前言          上一篇我们通过SpringMVC框架的快速入门已经了解了它的工作流程和各个组件,知道了引入SpringMVC框架后需要我们程序员手动开发的其实就是Handler 处理器和 View 视图,这一篇我们就从Handler 处理器(Controller层)开始入手

这篇文章主要讲解的知识点如下:

  • 参数绑定
    • 简单数据类型
    • POJO实体类型
    • 集合类型
  • SpringMVC编码过滤器 
  • SpringMVC日期转换格式器
  • 数据回显
    • Model的使用
  • 转发、重定向
  • 返回JSON文本
  • 文件上传

参数绑定

当项目中引入springmvc框架后,所有的请求流转将由springmvc进行控制,当客户端发送的请求中包含数据(也就是请求参数)时,那么该如何在controller层获取这些参数呢?

在 SpringMVC 中,提交请求的数据是通过方法形参来接收的。

也就是说从客户端请求的 key/value 数据会自动的和方法的参数进行匹配,然后将 key/value 数据绑定到 Controller 的形参上,我们就可以在Controller层使用这些请求中的参数,这就叫做参数绑定

在参数绑定过程中,会涉及到参数绑定组件,可以理解为将请求的数据类型转换成我们需要的数据类型,也叫做参数绑定转换器。在SprinifMVC框架中内置了很多参数转换器,只有在需要的情况下才需要我们自定义参数转换器,这个后面会介绍到 默认支持的参数类型 SpringMVC有默认支持的参数类型,我们可以直接在Controller层形参上给出这些默认对象的声明,就可以直接使用这些对象
对象说明
HttpServletRequest通过request对象获取请求信息例如url、ip、请求方式、请求参数和给未来页面传递数据
HttpServletResponse通过response对象获取请求信息例如设置响应类型、生成验证码、Cookie和返回json格式数据
HttpSession通过session对象获取session里存储的信息例如对会话级别的数据进行读写
Model通过model对象将数据填充到request域中向页面传递数据

接下来我介绍一下其他常用类型的参数绑定

为此我们先创建一个简单的表达页面用于提交数据

编辑index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title>参数绑定title>head><body><form action="/param" method="post">    用户名:<input type="text" name="username"><br/>    密码:<input type="text" name="password"><br/>    <input type="submit" value="提  交">form>body>html>
简单数据类型参数绑定

基本数据类型

基本数据类型包括byte、short、int、long、float、double、boolean、char八种,接下来我们以 int 为例

  • Controller控制层代码

@Controllerpublic class ParamController {    /**     * 简单类型参数     * @return     */    @RequestMapping("/param")    public ModelAndView param(int username, int password) {        System.out.println(username + " : " + password);        return null;    }}
  • 测试,输出结果

694bea0a7b72194c83da1f5b49e58665.png     ff2504bcbb623eb2ec32f84cc84d33ef.png

控制台打印出来了我们提交的表单数据

注意:表单中input的name值是和控制层的参数变量名保持一致,这样才能                    完成参数绑定。如果不一致的情况下就需要我们引入一个注解                               

@RequestParam 

使用这个注解,控制层可以使用任意形参,但是必须要保证注解的value值和表单的input的name值保持一致

    @RequestMapping("/param")    public ModelAndView param(@RequestParam("username") int name, int password) {        System.out.println("用户名:" + name);        System.out.println("密码:" + password);        return null;    }

控制台成功打印出我们的提交数据

ff2504bcbb623eb2ec32f84cc84d33ef.png

@RequestParam 注解细节

该注解有三个变量:value、required、defaultValue

  • value : 指定name属性的值是什么,一般情况下value属性可以省略不写,直接写值即可

  • required : 参数是否必须传递,可以是true或false

  • defaultValue : 设置默认值

注意: 我们这里的参数是基本数据类型,如果从表单传递过来的参数是""或者null的情况下,就会出现数据转换异常 所以在我们开发的过程中,为了避免传递过来的数据可能为空的情况下,最好将参数类型定义为包装类型,我们往下看

包装数据类型

包装数据类型包括Integer、Long、Byte、Double、Float、Short,(String 类型在这也是适用的),接下来我们以 Integer和String 为例

  • Controller控制层代码

    @RequestMapping("/param")    public ModelAndView param(String username, Integer password) {        System.out.println("用户名:" + username);        System.out.println("密码:" + password);        return null;    }

和基本数据类型基本一样,如果我们在表单处没有提交任何一个参数,那么String类型的数据就会显示为"",Integer类型的数据就会显示为null

cdfe5e5b0dbebfcf276fb94451c60fa8.png

SpringMVC编码过滤器

思考:

之前我们测试的参数绑定中,在Controller控制层没有对编码进行任何的操作,如果我们接收的是中文字符会是什么样子的呢?

02af0ce8163b91941336e5fceca9accc.png    0ffcf17dbbb8baeeb5e9fb4e122d87ec.png

唷~乱码了!

我们想到之前学过Servlet,可以设置request对象编码

request.setCharacterEncoding("utf-8”);
测试

8f601223cd046385057bb85db64a3418.png

唷~还是乱码!

因为SpringMVC框架接收参数是通过控制器中的无参构造方法,再经过具体业务方法的Object对象来得到具体的参数类型的

解决方法:SpringMVC已经给我们准备了一个编码过滤器,该过滤器只针对POST方法有效,只需要在web.xml文件中进行相关配置就可以

    <filter>        <filter-name>CharacterEncodingFilterfilter-name>        <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>        <init-param>            <param-name>encodingparam-name>                        <param-value>utf-8param-value>        init-param>    filter>    <filter-mapping>        <filter-name>CharacterEncodingFilterfilter-name>        <url-pattern>/*url-pattern>    filter-mapping>
这样就可以正常提交中文字码了

f06eb70e96b34f4105bc42b767bce511.png

POJO实体类型参数绑定 当需要接收客户端发送过来的多个数据时,我们在控制层通过声明方法参数一个一个的去接收就变的非常麻烦 我们是否可以在方法上声明对象类型的参数,通过对这些数据进行统一的接收,SpringMVC框架会自动的将接收过来的数据封装到对象中 普通POJO类型
  • 我们先定义一个User类
@Data@AllArgsConstructor@NoArgsConstructorpublic class User {    private String username;    private Integer password;}
注意:表单中input中的name属性只要和POJO实体类中的属性保持一致就可以映射成功
  • 编辑Controllerl类

   /**     * pojo实体类型参数     * @return     */    @RequestMapping("/param")    public ModelAndView param(User user) {        System.out.println(user);        return null;    }
  • 测试,输出结果
02af0ce8163b91941336e5fceca9accc.png   94dbba4f40161dd955ec42206808b436.png
  • 接下来我们在User实体中新添加一个成员变量(Date类型)

@Data@AllArgsConstructor@NoArgsConstructorpublic class User {    private String username ;    private String password;    private Date birthday;}
  • index.jsp表单提交页面中也添加一个input标签

 生日:type="text" name="birthday">
  • 测试,输出结果

e253f564a398fcfa834942a74f1b4ac3.png

bef689cea4538bc594c3adf2d41804ae.png

可以看到我们在表单提交页面输入的日期类型为 yyyy/MM/dd 类型,控制层可以正常接收,这是因为SpringMVC默认的日期格式就是这种,如果我们输入的是 yyyy-MM-dd 类型呢?
  • 测试,输出结果

aad0213a86dee9cdaa585c87844af84b.png

8d2bf66fee164d047b39884dd8e26d8d.png

结果出问题了,SpringMVC不支持这种类型的数据

解决方法:SpirngMVC提供了一个@InitBinder注解,用于指定自定义的日期转换格式,因此,我们只需要在Controller类中添加下面的代码即可,在接受日期类型的参数时,会自动按照自定义的日期格式进行转换。
  /* 自定义日期转换格式 */    @InitBinder    public void InitBinder (ServletRequestDataBinder binder){        binder.registerCustomEditor(Date.class,                new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true)        );    }
  • 再次测试,输出结果

2d6dcb61c3958e9bf202b8ed36b38909.png

上述我们字符串转日期格式的方式叫WebDataBinder方式,但这种方式有一个弊端是只能针对当前的Controller使用,如果有多个Controller需要进行格式转换的话就需要用到日期格式转换器

SpringMVC日期格式转换器

  • 自定义转换器

import org.springframework.core.convert.converter.Converter;/** * 日期格式转换器 * 需要实现Converter接口,将String类型转换成Date类型 */public class DateConverter implements Converter<String,Date> {    @Override    public Date convert(String date) {        //实现将字符串转成日期类型(格式是yyyy-MM-dd HH:mm:ss)        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");        try {            return dateFormat.parse(date);        } catch (ParseException e) {            e.printStackTrace();        }        //参数绑定失败返回null        return null;    }}
  • 配置dispatcher-servlet.xml

 <context:component-scan base-package="com.cn"/>        <mvc:annotation-driven conversion-service="conversionService">mvc:annotation-driven>        <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">        <property name="converters">            <list>                                <bean class="com.cn.util.DateConverter">bean>            list>        property>    bean>
  • 再次测试,输出结果

17e9799da6501eb9bea56397d563c4f8.png

包装POJO类型 包装POJO类型与普通POJO类型的区别是,包装类型POJO里有的成员变量是另一个POJO的属性,也就是POJO套POJO 这种组合的设计方法对于后期程序的扩展很有用,比如复杂的查询条件就需要包装到这种包装类型中
  • 新编辑一个实体类UserInfo

@Data@AllArgsConstructor@NoArgsConstructorpublic class UserInfo {    private String address;}
  • 在User实体中增加一个属性
@Data@AllArgsConstructor@NoArgsConstructorpublic class User {    private String username;    private String password;    private Date birthday;    private UserInfo userinfo;}
  • index.jsp表单提交页面中也添加一个input标签

 地址:type="text" name="userinfo.address">

注意:User对象中有userinfo属性,在表单提交代码中要使用 "属性名(对象类型的属性).属性名 "来定义input标签中的name值

  • 测试代码

  /**     * 包装POJO类型参数绑定     * @param user     * @return     */    @RequestMapping("/param")    public ModelAndView getParam(User user){        System.out.println(user.getUserinfo().getAddress());        return null;    }
  • 输出结果

b65992133b21ed802e2b3ca3de1e9074.png

集合类型参数绑定 数组类型 数组的绑定指的是从前台传过来同一类型的数据,我们在Conreoller层使用数组形参来接收数据
  • 编辑index.jsp表单提交页面(模拟选中多个复选框)

 type= type= type=
  • 编辑Controller层

 @RequestMapping("/param")    public ModelAndView param(String[] hobbies) {        for (String hobby : hobbies) {            System.out.println(hobby);        }        return null;    }
Controller层的方法形参值和表单提交页面input标签中的name值保持一致
  • 测试,输出结果

5e24a448fe59e54dc29801805e847d43.png

List类型 通常我们需要批量提交数据的时候(例如批量删除,修改等业务),往往将数据绑定到list再提交给Controller层
  • 创建一个UserList类,封装 List 属性

public class UserList {    private Listlist;}
  • index.jsp表单提交页面模拟提交多条用户信息

    用户名:<input type="text" name="list[0].username"><br/>    密码:<input type="text" name="list[0].password"><br/>    用户名:<input type="text" name="list[1].username"><br/>    密码:<input type="text" name="list[1].password"><br/>
  • 编辑Controller层

   @RequestMapping("/param")    public ModelAndView param(UserList userList) {        List users = userList.getList();        for (User user : users) {            System.out.println(user);        }        return null;    }
  • 测试,输出结果

f0cb2118eeed2c8f8eeadf9ae1fa9597.png

Map类型 Map类型参数绑定和List的方法一样,只不过是绑定的类型不一致而已
  • 创建一个UserMap类,封装 Map 属性

@Data@AllArgsConstructor@NoArgsConstructorpublic class UserMap {    private Map<String,User> map;}
  • index.jsp表单提交页面模拟提交多条用户信息

    用户名:<input type="text" name="map['one'].username"><br/>    密码:<input type="text" name="list['one'].password"><br/>    用户名:<input type="text" name="list['two'].username"><br/>    密码:<input type="text" name="list['two'].password"><br/>
  • 编辑Controller层
   @RequestMapping("/param")    public ModelAndView param(UserMap userMap) {        Map map = userMap.getMap();        for (Map.Entry entry : map.entrySet()) {            System.out.println(entry);        }        return null;    }
  • 测试,输出结果

b38fd5b1679907a241cfdb0b2f271dbb.png

到这里我们关于SpringMVC的参数绑定基本常用的就总结完毕了,其实原理都差不了多少,只是针对页面提交过来的类型,绑定的方式有些区别而已,多加练习基本就能掌握这些。 接下来我们思考控制层接收参数处理完业务后数据是怎么响应到页面上的? 数据回显 其实数据回显我们之前在其他文章中就已经使用过EL表达式在页面上过数据,其实这就叫做数据回显,本质其实就是获取request的值 在SpringMVC中,我们一般是将数据添加到Model,然后使用model把数据绑定到reques中 Model的使用 Model其实就是一个Map对象,我们把数据通过addAttribute方法添加到Model中后会自动保存在request域中,再通过转发将属性数据带到响应的页面中,然后通过 ${ } 来读取数据
  • Model中添加属性

 /**     * 测试Model对象     */    @RequestMapping("/testModel")    public String testModel(Model model){        /* 往Model添加属性 */        model.addAttribute("name", "桔子");        model.addAttribute("age", 18);        return "home";    }
  • 编辑home.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title>Titletitle>head><body>   用户名:${ name } <br/>   年龄:${ age }body>html>
  • 测试,输出结果

072ce8a0756c7a10a20c5aa5749c197d.png

转发和重定向在前面Servlet的request对象的学习中,我们通过request对象可是实现转发和重定向 同样SpringMVC中也提供了请求和重定向的方法,并且非常简单,我们一一介绍 转发
  • 编辑测试请求转发方法

    /**     * 测试请求转发(forward)     */    @RequestMapping("/testForward")    public String testForward(){        System.out.println("测试请求转发(forward)...");        return "forward:/hello";    }    @RequestMapping("/hello")    public String hello() {        return "hello";    }
  • 访问测试,输出结果

cf712df36c65ce2c4cb0a3b3d226149d.png

其实我们添加的forword就相当于之前学过的下面的代码
request.getRequestDispatcher("url").forward(req, resp);
特点:
  • 转发是一次请求,一次响应
  • 转发后地址栏没有发生变化,还是访问的/testForword地址
  • 转发前后的request和response对象也是同一个
重定向
  • 编辑测试重定向方法

    /*      *  测试请求重定向(redirect)     */    @RequestMapping("/testRedirect")    public String testRedirect(){        System.out.println("测试请求重定向(redirect)...");        return "redirect:/hello";    }
  • 访问测试,输出结果

787bcf01f7f9e96a8baa1fe22b9c3707.png

其实我们添加的redirect就相当于之前学过的下面的代码
response.sendRedirect(url)
特点:
  • 重定向是两次请求,两次响应
  • 重定向后地址栏发生了变化,之前访问的/testRedirect地址,变成了/hello地址
  • 重定向前后的request和response对象不是同一个
返回JSON文本

JSON(JavaScript Object Notation)是一种JS提供的轻量级的数据交换格式。

JSON在项目开发中是一种非常流行的数据交换格式。

我们如果想要返回给页面一个JSON文本,SpringMVC给我们提供了一个非常简便的注解——@ResponseBody
  • 首先我们需要添加两个JSON的jar包

              <dependency>            <groupId>org.codehaus.jacksongroupId>            <artifactId>jackson-core-aslartifactId>            <version>1.9.13version>        dependency>                <dependency>            <groupId>org.codehaus.jacksongroupId>            <artifactId>jackson-mapper-aslartifactId>            <version>1.9.13version>        dependency>
  • 编辑测试方法

   @RequestMapping("/testJson")    @ResponseBody    public List testJson(){        //模拟查询所有用户,将所有用户信息封装到List集合中        Listlist = new ArrayList();        list.add( new User("张三", 123) );        list.add( new User("李四", 222) );        //将所有用户的List集合以JSON格式响应        return list;    }
  • 输出结果

ede7be640772bb8d3736cef4d4389929.png

文件上传

文件的上传和下载基本上是web项目中经常中会用到的技术,比如在一些社交网站上上传一些图片和视频等

springmvc中由MultipartFile接口来实现文件上传。

  • 首先我们需要添加两个文件上传的jar包

               <dependency>            <groupId>commons-fileuploadgroupId>            <artifactId>commons-fileuploadartifactId>            <version>1.3.1version>        dependency>                <dependency>            <groupId>commons-iogroupId>            <artifactId>commons-ioartifactId>            <version>2.4version>        dependency>
  • 配置文件上传解析器

      <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">                <property name="maxUploadSize" value="5242880">property>    bean>
  • 编辑前端upload.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head>    <title>文件上传title>head><body><form action="/upload" method="post" enctype="multipart/form-data">    <input type="file" name="picture">    <input type="submit" value="图片上传">form>body>html>
  • 处理层Controller代码

@Controllerpublic class UploadController {    @RequestMapping("/upload")    //MultipartFile该对象就是封装了图片文件    public void upload(MultipartFile picture) {        System.out.println(picture.getOriginalFilename());    }    @RequestMapping("/testUpload")    public ModelAndView testUpload() {        return new ModelAndView("upload");    }}
  • 访问测试,输出结果

    efbf44c24f4b6329ac3a146b2f29cb4f.png

ff8a6823e30438aa86b822b56d9654b3.png

下一篇我们将继续介绍SpringMVC的统一异常管理、RESTful、拦截器等相关的知识,敬请期待 因为本人还是一枚正在路上的菜鸟,难免会有错误之处还望大家及时指正,如果对您有所帮助,别忘了点赞,再看噢~~~
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值