我是靠谱客的博主 风中衬衫,最近开发中收集的这篇文章主要介绍SpringMVC框架学习笔记(三)(数据传递,数据绑定,文件上传与下载),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

SpringMVC框架学习笔记(三)

    • 六、数据传递
      • 6.1 请求转发传递数据
        • (1)传统方式:HttpServletRequest请求转发
        • (2)使用`ModelAndView`请求转发(底层ModelMap)
            • 对`addObject`源码查看
        • (3)String作为请求转发返回类型传递数据(ModelMap,model和map)
      • 6.2 重定向传递数据
      • 6.3 会话和应用范围传递数据
      • 6.4 防止重复提交
    • 七、数据绑定
      • 7.1 简单数据绑定
        • (1)`HttpServletRequest`需要自己完成转换过程
        • (2)`@RequestParam`注解:功能强大
          • 初始方式
          • 简写方式:推荐
      • 7.2 占位符数据绑定
      • 7.3 自定义对象数据绑定
        • (1)单个对象的绑定:
        • (2)关联对象:不同的属性
          • 1. 关联对象classInfo:(不同属性)
          • 2. 关联对象group:(相同属性:使用类中的属性进行区分,并且直接建立关联关系)
          • 3. 同属性问题(推荐):可以通过第三方建立关联对象属性进行区分
      • 7.4 Map类型的数据绑定
    • 八、文件上传和下载
      • 8.1 文件上传的准备
      • 8.2 文件上传的步骤
        • (1)新建表单
        • (2)配置处理`multipart/form-data`解析器
        • (3)控制器数据绑定
      • 8.3 文件上传“套路”
      • 8.4 文件上传和下载
        • (1)文件上传保存数据(模拟操作)
        • (2)下载页面
    • 九、静态资源访问
      • (1)使用服务器默认的排除方案
      • (2)建立静态资源的映射路径

六、数据传递

SpringMVC应用中,我们经常需要在Controller将数据传递到JSP页面,除了可以通过HttpServletRequest域传递外,Spring
MVC还提供了两个Api,分别为Model接口和ModelMap类。

6.1 请求转发传递数据

6.1使用的结果页代码:

<body>
    <h3>EL表达式</h3>
    <h3>${requestScope.bookName}</h3>
    <h3>${requestScope["123"]}</h3>
    <h3>${integer}</h3>
    <h3>${string}</h3>
    <h3>${requestScope.dog.dogName}</h3>
</body>

可以使用HttpServletRequest传递数据,底层也是使用该类进行数据传递,但是进行封装

(1)传统方式:HttpServletRequest请求转发

@Controller
@RequestMapping("forword")
public class ForwordController {
    @Autowired
    private HttpServletRequest request;

    /**JavaWeb的形式*/
    @GetMapping("/data")
    public String m1(){
        request.setAttribute("bookName","北斗");
        request.setAttribute("123",999.9);//123特殊字符
        request.setAttribute("integer",888);//integer不是关键字
        request.setAttribute("string","羽化");//string不是关键字
        Dog dog = new Dog();
        dog.setDogName("黑皇");
        request.setAttribute("dog",dog);

        return "result01";
    }

}

在这里插入图片描述

(2)使用ModelAndView请求转发(底层ModelMap)

这是SpringMVC独有的ModelAndView对象,通过声明一个ModelAndView类型的对象,就可以使用这个对象来传值或者是指定跳转的页面路径。采用addObject()方法,来规定key和value

mav.addObject():当存储的数据没有指定类,默认是其对应引用数据类型的首字母小写
比如:mav.addObject("大圣");//String->string,key值为"string"

若果后面还有和此数据类型相同的数据mav.addObject("凌霄");//String->string
那么此时因为二者key值相同,所以显示的数据后者覆盖前者为"凌霄"

@GetMapping("/data")
    public ModelAndView m2(){
        ModelAndView mav = new ModelAndView();
        mav.setViewName("result01");
        mav.addObject("bookname","九天十地");
        mav.addObject("123", 666);
        /**当存储的数据没有指定类,默认是其对应引用数据类型的首字母小写*/
        mav.addObject(666);//int->Integer->integer
        mav.addObject("大圣");//String->string
        mav.addObject("凌霄");//String->string
        Dog d1 = new Dog();
        d1.setDogName("啸天");
        mav.addObject(d1);//d1->Dog->dog
        return mav;
    }

在这里插入图片描述

addObject源码查看
public ModelAndView addObject(Object attributeValue) {
    this.getModelMap().addAttribute(attributeValue);
    return this;
}

public ModelAndView addAllObjects(@Nullable Map<String, ?> modelMap) {
    this.getModelMap().addAllAttributes(modelMap);
    return this;
}
//调用this.getModelMap()返回ModelMap的类型,提供存储功能addAttribute(attributeName, attributeValue)
public ModelMap getModelMap() {
    if (this.model == null) {
        this.model = new ModelMap();//ModelMap进行实例化,形参构造方法就可以进行实例化
    }

    return this.model;
}

注意:此处代码用gerclass()方法查看返回值类型就是ModelAndView.

其底层用ModelMap实现

(3)String作为请求转发返回类型传递数据(ModelMap,model和map)

图片来自

  • ModelMap
 @GetMapping("/data03")
    public String m3(ModelMap modelMap){
        System.out.println("实际的堆内置类型"+modelMap.getClass());
        modelMap.addAttribute("bookname","柳树");
        modelMap.addAttribute("123", 999);
        /**当存储的数据没有指定类,默认是其对应引用数据类型的首字母小写*/
        modelMap.addAttribute(666);//int->Integer->integer
        modelMap.addAttribute("二师兄");//String->string
        modelMap.addAttribute("吃猪肉");//String->string
        Dog d1 = new Dog();
        d1.setDogName("啸天");
        modelMap.addAttribute(d1);//d1->Dog->dog
        return "result01";
    }

ModelMap是一个类,继承LinkedMap,因此为Map结构,可以使用Key/Value形式存储值。

源码:

 public class ModelMap extends LinkedHashMap<String, Object>
  • Map
    @GetMapping("/data04")
    public String m4(Map<String,Object> map){//BindingAwareModelMap
        System.out.println("实际的堆内置类型:"+map.getClass());
        //Map中提供的方法比较少,尽量少用
        map.put("bookName","柳树Map");
        map.put("123",7777.7);
        map.put("integer",666);
        map.put("string","狠人");
        Dog d1 = new Dog();
        d1.setDogName("小黑");
        map.put("dog",d1);//d1->Dog->dog
        return "result01";
    }

Map是一个接口,Map中提供的方法比较少,尽量少用

  • Model
   @GetMapping("/data05")
   public String m6(Model model){
       System.out.println("实际的堆内置类型:"+model.getClass());
       model.addAttribute("bookName","柳树model");
       model.addAttribute("123",7777.7);
       /**当存储的数据没有指定类,默认是其对应引用数据类型的首字母小写*/
       model.addAttribute(666);//int->Integer->integer
       model.addAttribute("断德");//String->string
       Dog d1 = new Dog();
       d1.setDogName("小黑");
       model.addAttribute(d1);//d1->Dog->dog
       return "result01";
   }
}

Model是一个接口,其实现类为ExtendedModelMap,继承了ModelMap类。
源码:
public class ExtendedModelMap extends ModelMap implements Model

上述代码运行后发现控制台输出其实际类型:
在这里插入图片描述

  • BindingAwareModelMap
    @GetMapping("/data06")
    public String m4(BindingAwareModelMap modelMap){
        System.out.println("实际的堆内置类型:"+modelMap.getClass());
        modelMap.addAttribute("bookName","柳树BindingAwareModelMap");
        modelMap.addAttribute("123",9999.9);
        /**当存储的数据没有指定类,默认是其对应引用数据类型的首字母小写*/
        modelMap.addAttribute(666);//int->Integer->integer
        modelMap.addAttribute("无始");//String->string
        Dog d1 = new Dog();
        d1.setDogName("小黑");
        modelMap.addAttribute(d1);//d1->Dog->dog
        return "result01";
    }

源码:
public class BindingAwareModelMap extends ExtendedModelMap
public class ExtendedModelMap extends ModelMap implements Model

所以这三者不论使用哪一 个最后都是在隐含模型中的

6.2 重定向传递数据

new String("一叶遮天".getBytes("UTF-8"),"ISO8859-1"));
设置中文编码

@Controller
@RequestMapping("/redirect")
public class RedirectController {
   
    @GetMapping("/data01")
    public ModelAndView m1() throws UnsupportedEncodingException {
        ModelAndView mav = new ModelAndView();
        mav.setViewName("redirect:/view/result02.jsp");
        mav.addObject("bookId",99);
        mav.addObject("bookName",new String("一叶遮天".getBytes("UTF-8"),"ISO8859-1"));//设置中文编码
        mav.addObject("hobby",new String[]{"100","200"});
        return mav;
    }
<body>
    <h3>${param.bookId}</h3>
    <h3>${param.bookName}</h3>
    <h3>${paramValues.hobby[0]}</h3>
    <h3>${paramValues.hobby[1]}</h3>
</body>

重定向执行结果:
http://127.0.0.1:8080/mvc/view/result02.jsp?bookId=99&bookName=一叶遮天hobby=100&hobby=200:自动拼接

6.3 会话和应用范围传递数据

package com.framework.web;
@Controller
@RequestMapping("/server")
public class SessionApplicationController {
	@Autowired
	private HttpSession session;
	@Autowired
	private ServletContext application;
	@GetMapping("/demo01")
	@ResponseBody
	public void m1(){//存储数据的过程
		session.setAttribute("bookName","session-红楼梦");
		session.setAttribute("author","session-曹雪芹");
		application.setAttribute("bookName","application-西游记");
		application.setAttribute("author","application-吴承恩");
	}
	@GetMapping("/demo02")
	@ResponseBody
	public void m2(){//移除数据
		session.removeAttribute("bookName");
	}
	@GetMapping("/demo03")
	@ResponseBody
	public void m3(){//注销session
		session.invalidate();
	}
}

6.4 防止重复提交

对应放置表单的重复提交,我们可以使用JavaScript进行控制或者使用Token,SpringMVC提供了这种特殊场景的数据的传递方式

Controller->重定向->Controller->请求转发->JSP

在做一般的登录操作时候会用到这种方式

@Controller
@RequestMapping("/flash")
public class FlashValueController {
    @GetMapping("/data01")
    public String m1(RedirectAttributes ra){
        ra.addFlashAttribute("message","您的账号或者密码错误,请重新登录");
        return "redirect:/flash/data02";
    }
    @GetMapping("/data02")
    public String m2(){
        return "show";
    }
}

七、数据绑定

在我们学习Java Web阶段通过HttpServletRequest获取客户端数据的时候,获取的类型(String/String[]/Map<String,String[]>)形式,Spring MVC框架内部提供了数据绑定的方式(绑定的过程中可以完成数据类型转换,提供大量内置数据类型转换器)

客户端通过路径或者表单传递数据->映射路径找到处理器Controller->传递参数->绑定进行处理(WebDataBinder)->在绑定的过程中完成数据的转换或者数据的验证

7.1 简单数据绑定

基本数据类型、包装类、字符串、数组、**日期(注意)**等类型

(1)HttpServletRequest需要自己完成转换过程

在SpringBoot的控制器的方法中,如果return一个字符串,那么程序默认会跳转到这个字符串所表示的页面,而@ResponseBody注解的作用就是阻止这个功能的,这个注解可以让return的字符串直接返回到页面中或者直接返回到ajax的执行成功方法中。

@Controller
@RequestMapping("/simple")
public class SimpleDataController {
	@Autowired
	private HttpServletRequest request;
	//<a href="simple/test00?id=90&money=80&hobby=basketball&hobby=足球">回顾:传统获取方式</a><br/>
	@GetMapping("/test00")
	@ResponseBody
	public void m1(){
		String idStr = request.getParameter("id");
		int id = Integer.parseInt(idStr);//自己处理
		System.out.println("id = " + id);
		String moneyStr = request.getParameter("money");
		double money = Double.parseDouble(moneyStr);
		System.out.println("money = " + money);
		String[] hobbies = request.getParameterValues("hobby");
		System.out.println("Arrays.toString(hobbies) = " + Arrays.toString(hobbies));
	}

}

${param.name} 等价于 request.getParamter(“name”),这两种方法一般用于服务器从页面或者客户端获取的内容,这些内容都是String的。
${requestScope.name} 等价于 request.getAttribute(“name”),一般是从服务器传递结果到页面,在页面中取出服务器端保存的值!
——来自

(2)@RequestParam注解:功能强大

属性说明:
@RequestParam(name = "id",required = true) Integer userId
将客户端属性名称为"id"的值赋值给这个形参.
其中required 作用是必须传递
defaultValue作用是赋值一个默认值

<a href="simple/test01?bookName=西游记&id=90&money=80&hobby=basketball&hobby=足球">@RequestParam的使用说明-正常测试</a><br/>
<a href="simple/test01?bookName=西游记&money=80&hobby=basketball&hobby=足球">@RequestParam的使用说明-400错误</a><br/>
<a href="simple/test01?id=90&hobby=basketball&hobby=足球">@RequestParam的使用说明-默认值测试</a><br/>

@InitBinder只在@Controlle中注解方法来为这个控制器注册一个绑定器初始化方法,方法只对本控制器有效。

初始方式
@GetMapping("/test01")
@ResponseBody
public void m1(
    @RequestParam(name = "id",required = true) Integer userId,//String=>Integer
    @RequestParam(name = "bookName",required = false) String book_name,//String=>String
    @RequestParam(name="money",required = false,defaultValue = "123.456")  Double bookMoney,//String=>Double
    @RequestParam("hobby")	 String[] hobbyArray){//String=>String[] 简写方式
    System.out.println("userId = " + userId);
    System.out.println("book_name = " + book_name);
    System.out.println("bookMoney = " + bookMoney);
    System.out.println("hobbyArray = " + Arrays.toString(hobbyArray));
}
@InitBinder
public void initBinder(WebDataBinder binder){
    System.out.println(Math.random()+".....绑定器,可以自定义");
}

就算是null也需要绑定转换
未传递id,则返回400错误

简写方式:推荐

当传递参数的名称和形参相同时,可省略 @RequestParam(name = "id",required = true)这部分代码
设置只要数据合适,可以直接转换:Integer[] hobbyArray
缺点是不能设置默认值

<a href="simple/test02?bookName=西游记&id=90&money=80&hobby=999&hobby=777">简写方式=推荐=注意规则形参名称和传递名称一致</a><br/>
@GetMapping("/test02")
@ResponseBody
public void m2(/*@RequestParam(name = "id",required = false)*/ Integer id,
               String bookName,Double money,Integer[] hobbyArray){
    System.out.println("id = " + id);
    System.out.println("bookName = " + bookName);
    System.out.println("money = " + money);
    System.out.println("hobbyArray = " + Arrays.toString(hobbyArray));
}
@InitBinder
public void initBinder(WebDataBinder binder){
    System.out.println(Math.random()+".....绑定器,可以自定义");
}

绑定器绑定了四次

  • 绑定Map类型()
<h3>Map类型</h3>
<a href="simple/test03?bookName=西游记&id=90&money=80">Map类型绑定,绑定的执行次数</a><br/>
@GetMapping("/test03")
@ResponseBody
public void m2(@RequestParam Map<String,Object> tempMap){
    System.out.println("tempMap = " + tempMap);
}
@InitBinder
public void initBinder(WebDataBinder binder){
    System.out.println(Math.random()+".....绑定器,可以自定义");
}

7.2 占位符数据绑定

占位符我们推荐传递简单的数据类型,占位符支持正则表达式

@PathVariable是spring3.0的一个新功能:接收请求路径中占位符的值

@Controller
@RequestMapping("/path")
public class PathDataController {

	@GetMapping("/test01/{id}/{name}")
	@ResponseBody
	public void m1(@PathVariable("id") Integer userId,@PathVariable/*("name")*/ String name){
		System.out.println("userId = " + userId);
		System.out.println("name = " + name);
	}
	@GetMapping("/test02/{id}/{name}")
	@ResponseBody
	public void m1(@PathVariable Map<String,Object> tempMap){
		System.out.println("tempMap = " + tempMap);
	}
	@InitBinder
	public void initBinder(WebDataBinder binder){
		System.out.println(Math.random()+".....绑定器,可以自定义");
	}

}
<h3>占位符传递数据</h3>
<a href="path/test01/100/悟空">占位符传递数据</a><br/>
<a href="path/test02/100/悟空">占位符传递数据-Map绑定</a><br/>

转换map类型不会经过绑定 只有类型对类型才会绑定
占位符绑定的时候不可省略@PathVariable标签

7.3 自定义对象数据绑定

将客户端传递的数据直接转换成Java自定义对象,了解默认规则

(1)单个对象的绑定:

传递的名称为类中的属性名称,可以完成成String->对象的转换

当传递属性名称与类中不同时,输出结果为null

public class Student {	
	private String name;
	private Integer age;
	private Integer[] hobbies;
}
<form action="object/data01">
    学生姓名:<input type="text" name="name"/><br/>
    学生年龄:<input type="text" name="age"/><br/>
    爱好:<!-- 经典的多选控件,复选框和多选列表 -->
    <select name="hobbies" multiple>
        <option value="100">篮球</option>
        <option value="200">足球</option>
        <option value="300">排球</option>
    </select>
    <br/>
    <button>简单对象</button>
</form>
@Controller
@RequestMapping("/object")
public class ObjectBinderController {
    @GetMapping("/data01")
    @ResponseBody
    public Student m1(int age, Student student){
        System.out.println("age = " + age);

        return student;
    }

    @InitBinder
    public void initBinder(WebDataBinder binder){
        System.out.println(Math.random()+".....绑定器,可以自定义");
    }

}

在这里插入图片描述

(2)关联对象:不同的属性

1. 关联对象classInfo:(不同属性)
public class ClassInfo {
    private String className;
    private Integer classNumber;
}
  • xml文件
<form action="object/data02">
            学生姓名:<input type="text" name="name"/><br/>
            学生年龄:<input type="text" name="age"/><br/>
            爱好:<!-- 经典的多选控件,复选框和多选列表 -->
            <select name="hobbies" multiple>
                <option value="100">篮球</option>
                <option value="200">足球</option>
                <option value="300">排球</option>
            </select><br/>
            <!-- Student中关联对象的属性建立关联关系 -->
            班级名称:<input type="text" name="className"><br/>
            班级人数:<input type="text" name="classNumber"><br/>
           
            <br/>
            <button>关联对象和同属性对象区分</button>
  • 测试文件
 @GetMapping("/data02")
    @ResponseBody
    public Student m1(Student student , ClassInfo classInfo){
        //手动建立关联
        student.setClassInfo(classInfo);

        return student;
    }

在这里插入图片描述

2. 关联对象group:(相同属性:使用类中的属性进行区分,并且直接建立关联关系)
public class Group {
    private String name;
    private Integer age;
}
  • student对象:
public class Student {
    private String name;
    private Integer age;
    private Integer[] hobbies;

    //关联对象-不同属性
    private ClassInfo classInfo;

    //关联对象-相同属性
    private Group group;
}
  • group对象:
public class Group {
    private String name;
    private Integer age;

如果直接小组名称:<input type="text" name="name"/><br/>这样写,返回的student中学生名字会有两个值,group名字同样有两个

属性名称相同时,在xml配置中标明类名前缀:如name="group.name"
测试文件就不用手动建立关联

  • xml文件:
 <form action="object/data03">
            学生姓名:<input type="text" name="name"/><br/>
            学生年龄:<input type="text" name="age"/><br/>
            爱好:<!-- 经典的多选控件,复选框和多选列表 -->
            <select name="hobbies" multiple>
                <option value="100">篮球</option>
                <option value="200">足球</option>
                <option value="300">排球</option>
            </select><br/>
            <!-- Student中关联对象的属性建立关联关系 -->
            班级名称:<input type="text" name="classInfo.className"><br/>
            班级人数:<input type="text" name="classInfo.classNumber"><br/>
            小组名称:<input type="text" name="group.name"/><br/>
            小组年龄:<input type="text" name="group.age"/><br/>
            <br/>
            <button>关联对象和同属性对象区分</button>
  • 测试文件
  @GetMapping("/data03")
    @ResponseBody
    public Student m1(Student student , ClassInfo classInfo, Group group){

        return student;
    }
    @InitBinder
    public void initBinder(WebDataBinder binder){
        System.out.println(Math.random()+".....绑定器,可以自定义");
    }

在这里插入图片描述

3. 同属性问题(推荐):可以通过第三方建立关联对象属性进行区分
 <form action="object/data04">
            学生姓名:<input type="text" name="student.name"/><br/>
            学生年龄:<input type="text" name="student.age"/><br/>
            爱好:<!-- 经典的多选控件,复选框和多选列表 -->
            <select name="student.hobbies" multiple>
                <option value="100">篮球</option>
                <option value="200">足球</option>
                <option value="300">排球</option>
            </select><br/>
            老师姓名:<input type="text" name="teacher.name"/><br/>
            老师年龄:<input type="text" name="teacher.age"/><br/>
            爱好:<!-- 经典的多选控件,复选框和多选列表 -->
            <select name="teacher.hobbies" multiple>
                <option value="100">剑道</option>
                <option value="200">养雕</option>
                <option value="300">高人寂寞</option>
            </select><br/>
            <br/>
            <button>同属性对象推荐方式</button>
        </form>
</form>
public class MyModel {

	private Teacher teacher;
	private Student student;

}
@GetMapping("/data04")
@ResponseBody
public MyModel m3(MyModel myModel){
    return myModel;
}
@InitBinder
public void initBinder(WebDataBinder binder){
    System.out.println(Math.random()+".....绑定器,可以自定义");
}

在这里插入图片描述

7.4 Map类型的数据绑定

通过返回对象名称[自定义属性]来完成
学生年龄:<input type="text" name="queryMap[studentAge]"/><br/>

自定义返回对象的属性值:

  <form action="object/data05">
            学生姓名:<input type="text" name="queryMap[studentName]"/><br/>
            学生年龄:<input type="text" name="queryMap[studentAge]"/><br/>
            爱好:<!-- 经典的多选控件,复选框和多选列表 -->
            <select name="queryMap[studentHobbyArray]" multiple>
                <option value="100">篮球</option>
                <option value="200">足球</option>
                <option value="300">排球</option>
            </select><br/>
            老师姓名:<input type="text" name="queryMap[teacherName]"/><br/>
            老师年龄:<input type="text" name="queryMap[teacherAge]"/><br/>
            爱好:<!-- 经典的多选控件,复选框和多选列表 -->
            <select name="queryMap[teacherHobbyArray]" multiple>
                <option value="100">剑道</option>
                <option value="200">养雕</option>
                <option value="300">高人寂寞</option>
            </select><br/>
            <br/>
            <button>关联对象和同属性对象区分</button>
        </form>
  • 第三放对象文件
public class MyModel {
    private Student student;
    private Teacher teacher;

    private Map<String,Object> queryMap;
    }
  • 测试文件
 @GetMapping("/data05")
    @ResponseBody
    public MyModel m2(MyModel myModel){

        return myModel;
    }

在这里插入图片描述

八、文件上传和下载

文件上传也是数据(二进制流的方式multipart/form-data),需要将该内容类型处理成Java对象(commons-fileupload.jar或者Servlet 3.0),Spring MVC已经封装了这两种方式(一种二进制流的解析器,当发现是multipart/form-data,看你默认启动那种解析器的实现方式处理)

8.1 文件上传的准备

(1)客户端文件上传的约定

  • 必须使用post请求,不支持(PUT/DELETE
    • 可以使用表单
    • 可以使用Ajax
  • 传递的文件类型,必须设置为multipart/form-data内容类型
  • 文件域(单个或者多个multiple属性)

(2)服务端文件上传的约定

  • commons-fileupload.jar工具类的支持
  • 配置解析器处理multipart/form-data
  • 处理成MultipartFile或者MultipartFile[]

8.2 文件上传的步骤

(1)新建表单

 <form action="attr01", method="post", enctype="multipart/form-data">
      普通控件<input type="text" name="userName"><br/>
      文件1:<input type="text" name="myFile"><br/>
      <button>文件上传</button>
    </form>

(2)配置处理multipart/form-data解析器

前端控制器给解析器设置了默认名称

public class DispatcherServlet extends FrameworkServlet {
    public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
}   

使用解析器id名称只能叫multipartResolver

<!-- 文件上传的解析器,固定名称 id="multipartResolver" -->
    <bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
        <!-- 设置上传的编码格式 -->
        <property name="defaultEncoding" value="UTF-8"/>
        <!-- 上传所有文件总大小 -->
        <property name="maxUploadSize" value="#{1024*1024*50}"/>
        <!-- 单个文件大小 -->
        <property name="maxUploadSizePerFile" value="#{1024*1024*5}"/>
        <!-- 设置缓存 -->
        <property name="maxInMemorySize" value="2048"/>
        <!-- 延迟上传,提供上传效率 -->
        <property name="resolveLazily" value="true"/>
        <!-- 临时上传的目录 -->
        <property name="uploadTempDir" value="D:/Temp"/>
    </bean>

(3)控制器数据绑定

@Controller
public class uploadFileController {
    @PostMapping("/attr01")
    @ResponseBody
    public void upload01(String userName, MultipartFile myFile){
        System.out.println("堆中实际的类型:"+myFile.getClass().getName());
        System.out.println("普通控件 = " + userName);
        System.out.println("文件名称:"+myFile.getOriginalFilename());
        System.out.println("文件大小:"+myFile.getSize()+"B(字节)");
        System.out.println("文件类型(MIME):"+myFile.getContentType());
        System.out.println("控件名称:"+myFile.getName());
        //System.out.println("输入流:"+myFile.getInputStream());
        //System.out.println("字节数组:"+myFile.getBytes());
    }

在这里插入图片描述
(4)文件上传的方式
两种方式
一是输入输出流
二是springmvc封装的方法transferTo()

<form action="attr02" method="post" enctype="multipart/form-data">
    普通的控件:<input type="text" name="userName"><br/>
    文件1:<input type="file" name="myFile"><br/>
    <button>文件上传</button>
</form>
<form action="attr03" method="post" enctype="multipart/form-data">
    普通的控件:<input type="text" name="userName"><br/>
    文件1:<input type="file" name="myFile"><br/>
    <button>文件上传</button>
</form>
//输入输出流上传
@PostMapping("/attr02")
@ResponseBody
public void upload02(String userName, MultipartFile myFile) throws IOException {
    InputStream in = myFile.getInputStream();
    OutputStream out = new FileOutputStream("D:/upload/"+myFile.getOriginalFilename());
    IOUtils.copy(in,out);
}
@PostMapping("/attr03")
@ResponseBody
public void upload03(String userName, MultipartFile myFile) throws IOException {
    myFile.transferTo(new File("D:/upload/"+myFile.getOriginalFilename()));
}

在这里插入图片描述

8.3 文件上传“套路”

前文写过

@Autowired
    private ServletContext appliaction;
    @PostMapping("/attr04")
    @ResponseBody
    public void upload04(String userName, MultipartFile myFile) throws IOException {
        //1.获取服务器上传文件的所在目录
        String path = appliaction.getRealPath("/attr/");
        //2.跟磁盘建立联系
        File folder = new File(path);
        if(!folder.exists()){//判断目录是否存在
            folder.mkdirs();//创建文件夹
        }
        //3.获取上传文件的名称
        String fileName = myFile.getOriginalFilename();
        //4.获取上传文件名称的后缀名称
        String ext = FilenameUtils.getExtension(fileName);
        //5.创建新的文件名称(唯一)
        String newFileName = getUniqueFileName()+"."+ext;
        //6.文件上传(不做验证,因为在前端可以设置验证)
        myFile.transferTo(new File(path+"/"+newFileName));
    }
    public static String getUniqueFileName(){
        return UUID.randomUUID().toString().replaceAll("-","");
    }

在这里插入图片描述

8.4 文件上传和下载

目的:知道文件下载的3种方式,引出静态资源的访问问题。

(1)文件上传保存数据(模拟操作)

 @PostMapping("/attr05")
    public String upload04(String userName, MultipartFile myFile, Model model) throws IOException {
        //1.获取服务器上传文件的所在目录
        String path = appliaction.getRealPath("/attr/");
        //2.跟磁盘建立联系
        File folder = new File(path);
        if(!folder.exists()){//判断目录是否存在
            folder.mkdirs();//创建文件夹
        }
        //3.获取上传文件的名称
        String fileName = myFile.getOriginalFilename();
        model.addAttribute("showName", fileName);//元素内容
        //4.获取上传文件名称的后缀名称
        String ext = FilenameUtils.getExtension(fileName);
        //5.创建新的文件名称(唯一)
        String newFileName = getUniqueFileName()+"."+ext;
        model.addAttribute("serverFileName",newFileName);//添加到href中
        //6.文件上传(不做验证,因为在前端可以设置验证)
        myFile.transferTo(new File(path+"/"+newFileName));

        return "download";
    }

(2)下载页面

<body>
    <h3>1.简单的下载,直接访问资源即可(若浏览器支持则直接打开,不支持则下载)</h3>
    <a href="attr/${requestScope.serverName} ">${showName}</a>
    <h3>2.H5中的download属性强制下载</h3>
    <a href="attr/${requestScope.serverName}" download="${requestScope.showName}">${showName}</a>
    <h3>3.二进制流的方式下载</h3>>
    <a href="download?show=${showName}&real=${serverName}">${showName}_download</a>
</body>

只有第三种可正常下载,前两者报错:
No mapping for GET /mvc/attr/0ae503efb5fb4e42bf9c6e81614dfe83.md

原因:
所有的请求都被前端控制器DispatcherServlet处理,通过URL映射找到处理Controller,请求找不到NO Mapping
如何解决:

静态资源无法被直接访问,那么我们需要做到当访问的是静态资源的时候,让DispatcherServlet对其不处理

流的方式下载

 @GetMapping("/download")
    public ResponseEntity<byte[]> downloadFile(String show, String real) throws Exception {
        String path = appliaction.getRealPath("/attr/");
        File file = new File(path+"/"+real);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
        show = new String(show.getBytes("UTF-8"),"ISO8859-1");
        httpHeaders.setContentDispositionFormData("attachment",show);
        return new ResponseEntity<>(FileUtils.readFileToByteArray(file),httpHeaders, HttpStatus.CREATED);
    }

九、静态资源访问

(1)使用服务器默认的排除方案

当我们启动服务器的时候,会优先实例化WEB服务器提供的默认的Servlet(default),在该Servlet中有对静态资源的处理

如tomcat中web.xml文件里关于注册的servlet代码:

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>0</param-value>
    </init-param>
    <init-param>
        <param-name>listings</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

配置方案如下:

<!-- 方式一:排除静态资源,需要我们自己设置完整路径 -->
<mvc:default-servlet-handler default-servlet-name="default"/>

现在文件下载的demo中,三种下载方式皆可正常下载
在这里插入图片描述

(2)建立静态资源的映射路径

mvc:resources 参数说明:

<mvc:resources mapping="/映射的路径/**" location="本地静态资源的位置"/>=>location+**=真实的资源位置

<!--方式二:静态资源映射路径-->
    <mvc:resources mapping="/love/**" location="/attr/"/>
    <mvc:resources mapping="/abcd/**" location="/attr/"/>
    <mvc:resources mapping="/kkk/**" location="/attr/"/>
 <h3>4.映射路径</h3>
    <a href="love/${requestScope.serverName} ">${showName}</a>
    <a href="abcd/${requestScope.serverName} ">${showName}</a>
    <a href="kkk/${requestScope.serverName} ">${showName}</a>

如若这样配置src="images/a/b/c/d.jpg"
那么真实的位置 为/attr/a/b/c/d.jpg

最后

以上就是风中衬衫为你收集整理的SpringMVC框架学习笔记(三)(数据传递,数据绑定,文件上传与下载)的全部内容,希望文章能够帮你解决SpringMVC框架学习笔记(三)(数据传递,数据绑定,文件上传与下载)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部