SpringMVC原理、介绍及配置

SpringMVC

  Spring MVC是Spring提供的一个强大而灵活的web框架。借助于注解,Spring MVC提供了几乎是POJO的开发模式,使得控制器的开发和测试更加简单。这些控制器一般不直接处理请求,而是将其委托给Spring上下文中的其他bean,通过Spring的依赖注入功能,这些bean被注入到控制器中。

  Spring MVC主要由DispatcherServlet、处理器映射、处理器(控制器)、视图解析器、视图组成。

两个核心:

  处理器映射:选择使用哪个控制器来处理请求.

  视图解析器:选择结果应该如何渲染.

Servlet有哪些功能:

  1. 根据URL 找到Servlet : 解析请求 -----> 找到对应的Servlet

  2. 处理请求 : 获取请求的头信息 获取请求的数据

  3. 响应 : JSP HTML JSON Servlet:

    1. 将JSP内容,根据格式渲染HTML页面

    2. 将HTML内容,直接渲染成HTML页面

    3. JSON数据解析 : 字符串 resp.setContentType ("text/json;charset=UTF-8") :封装了JSON对象 Javascript对象

    4. Servlet解析,调用
      解析:解析
      渲染:告诉浏览器 数据格式
     Servlet :

      1.解析URL
      2.处理请求
      3.处理数据
      4.渲染视图

  尽可能职能是单一的,但是此时Servlet自身职能相对较多. 地址 各种if

  其二,本身Servlet 每个只能处理一个请求 。Service,当请求多时,需要定义多个Servlet

  对象多,代码复用性降低,性能也会降低。

基于Servlet可能存在的问题:

  Servlet调用Service:AService  BService : 业务处理.

  Spring对Servlet进行了封装:SpringMVC,这个框架只充当控制层.

SpringMVC原理图

springMVC架构流程:

​ 1. 用户发送请求到前端控制器DispatcherServlet

​ 2. DispatcherServlet 收到请求调用 HanderMapping 处理器映射器

​ 3. 处理器映射器根据请求 URL 找到具体的处理器,生成处理器对象及处理器拦截器(若有则生成)一并返回给 DispatcherServlet

​ 4. DispatcherServlet 通过 HandlerAdapter 处理器适配器调用处理器

​ 5. 执行处理器 Controller (也叫后端控制器)

​ 6. Controller 执行完成后返回 ModeAndView

​ 7. HandlerAdapter 将 controller 执行结果 ModeAndView 返回给 DispatcherServlet

​ 8. DispatcherServlet 将 ModeAndView 传给 ViewReslover 视图解析器

​ 9. ViewReslover 解析后返回具体 View

  1. DispatcherServlet 对 View 进行渲染视图(即将模型数据填充至视图中)

  2. DispatcherServlet 响应用户

springmvc 的三大组件

  处理器映射器(HanderMapping)处理器适配器(HandlerAdapter)视图解析器(ViewReslover)

springMVC流程原理:
  客户端(浏览器)发送请求到DispatcherServlet(调度器),DispatcherServlet(调度器)收到请求后,根据请求调用HandlerMapping(处理器映射器),HandlerMapping(处理器映射器)根据请求的URL找到具体的处理器,处理器生成处理器对象返回给DispatcherServlet(调度器),DispatcherServlet(调度器)通过HandlerAdapter(处理器适配器)调用Handler(处理器),Handler(处理器)处理相应的Service(业务层)业务逻辑,Handler(处理器)处理完成后找到ModelAndView(模型视图处理器)对象(Model是返回的数据对象(解析数据),View是一个逻辑上的View)传给ViewResolver(视图映射器)查找对应的View(逻辑视图)进行视图渲染(实际视图),DispatcherServlet(调度器)把返回的Model传给View,通过View响应给客户端(浏览器)。

1. DispatcherServlet接口:

  Spring提供的前端控制器,所有的请求都有经过它来统一分发。在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。

2. HandlerMapping接口:

  能够完成客户请求到Controller映射。

3. Controller接口:

  需要为并发用户处理上述请求,因此实现Controller接口时,必须保证线程安全并且可重用。

  Controller将处理用户请求,这和Struts Action扮演的角色是一致的。一旦Controller处理完用户请求,则返回ModelAndView对象给DispatcherServlet前端控制器,ModelAndView中包含了模型(Model)和视图(View)。

  从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型(Model)和视图(View)。

4. ViewResolver接口:

  Spring提供的视图解析器(ViewResolver)在Web应用中查找View对象,从而将相应结果渲染给客户。

SpringMVC使用

  1. 下载相关jar包,由于SpringMVC是Spring提供的框架,Spring的jar中,,包含SpringMVC相关jar包
spring-web-4.3.24.RELEASE.jar
spring-webmvc-4.3.24.RELEASE.jar
  1. 配置DispatcherServlet,让这个Servlet处理所有请求
<!-- 配置DispatcherServlet  调度器 -->
<servlet>
  	<servlet-name>springmvc</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  	<!-- 配置SpringMVC的映射器需要的文件 -->
  	<init-param>
  		<!-- 处理器映射器文件属性名 -->
  		<param-name>contextConfigLocation</param-name>
  		<!-- 具体的处理器文件 -->
  		<param-value>classpath:spring-mvc.xml</param-value>
  	</init-param>
  	<!-- 配置启动时机 -->
  	<load-on-startup>1</load-on-startup>
</servlet>
  
<servlet-mapping>
  	<servlet-name>springmvc</servlet-name>
  	<url-pattern>*.do</url-pattern>
</servlet-mapping>
  1. 定义处理器Handler

方式一:

package com.sxt.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.HttpRequestHandler;

public class Controller01 implements HttpRequestHandler   {
	@Override
	public void handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setAttribute("name", "Hello  Spring MVC");
		//跳转到 info.jsp
		request.getRequestDispatcher("info.jsp").forward(request, response);
	}

}

方式二:

package com.sxt.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class Controller02 implements Controller {

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		ModelAndView modelAndView = new ModelAndView();
		// 设置model数据
		modelAndView.addObject("name", "Hello Spring MVC");
		// 设置视图地址
		modelAndView.setViewName("info.jsp");
		return modelAndView;
	}

}
  1. 配置处理器,让调度器通过处理器映射器找到处理器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
	<!-- 处理器的配置文件 -->
	<!-- 注册处理器 -->
	<bean name="/controller01.do" class="com.sxt.controller.Controller01"></bean>
	<bean name="/controller02.do" class="com.sxt.controller.Controller02"></bean>
	<!-- 扫描注解 -->
	<context:component-scan base-package="com.sxt"></context:component-scan>
	<!-- 让 mvc 注解生效  -->	
	<mvc:annotation-driven></mvc:annotation-driven>
</beans>
  1. 请求
http://127.0.0.1:8080/springmvc/controller01.do

注解版

注解方式:

<!-- 扫描注解 -->
<context:component-scan base-package="com.sxt"></context:component-scan>
<!-- 让 mvc 注解生效  -->	
<mvc:annotation-driven></mvc:annotation-driven>

定义处理器

package com.sxt.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class Controller03 {

	@RequestMapping("/hello.do")
	public void hello(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException {
		req.setAttribute("name", "Hello Spring MVC");
		req.getRequestDispatcher("info.jsp").forward(req, resp);
	}
	
	@RequestMapping("/hello1.do")
	public ModelAndView hello1()  {
		ModelAndView  modelAndView = new ModelAndView();
		modelAndView.addObject("name",  "Hello Spring MVC");
		modelAndView.setViewName("info.jsp");
		return modelAndView;
	}
	
	
	@RequestMapping("/hello2.do")
	public String hello2(Model model)  {
		model.addAttribute("name",  "Hello Spring MVC");
		return "info.jsp";
	}
}

SpringMVC初始化流程:

DispatcherServlet : ---  init

DispatcherServlet 中没有init 方法
	|--- DispatcherServlet的父类:FrameworkServlet
			|--- FrameworkServlet 没有init方法 : FrameworkServlet的父类
				|--- HttpServletBean 中init方法 :   initServletBean () :
					|--- FrameworkServlet.initServletBean()
							|--- FrameworkServlet:initWebApplicationContext()
									|---FrameworkServlet.createWebApplicationContext() : 加载  springmvc的配置文件,且初始化handler对象
									|--- FrameworkServlet.onRefresh() : DispatcherServlet.onRefresh(WebApplicationContext)
									|--- DispatcherServlet.initStrategies(ApplicationContext) : 初始化DispatcherServlet 从DispatcherServlet.properties 进行默认的配置

@RequestMapping

@GetMapping/@PostMapping

value/path : 映射地址:

  该注解可以使用在类上面,也可以使用在方法上面.映射地址,是按照类上面该注解的value/path属性值与方法上面value/path属性进行拼接,组成URL路径.

method : 支持的请求方式.若不写,则默认GET和POST请求都支持.

在Spring新的版本中,使用 @PostMapping代理method为post,@GetMapping代替了method为get

params:限定请求中必须含有的参数

headers:限定请求中必须包含的请求头信息

consumes:限定请求的数据格式

produces:限定返回的数据格式

数据绑定-获取请求参数

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="user/add.do">
	<p>用户名:<input type="text"  name="userName1"/></p>
	<p>密码:<input type="text"  name="password"/></p>
	<p>年龄:<input type="text"  name="age"/></p>
	<input type="submit" value="提交">
</form>
<hr>
<form action="user/add2.do">
	<p>用户名:<input type="text"  name="userName"/></p>
	<p>密码:<input type="text"  name="password"/></p>
	<p>年龄:<input type="text"  name="age"/></p>
	<input type="submit" value="提交">
</form>
<hr>
<form action="user/add3.do">
	<p>用户名:<input type="text"  name="userName1"/></p>
	<p>密码:<input type="text"  name="password1"/></p>
	<p>年龄:<input type="text"  name="age1"/></p>
	<input type="submit" value="提交">
</form>
<hr>
<form action="user/add4.do">
	<p>用户名:<input type="text"  name="userName1"/></p>
	<p>密码:<input type="text"  name="password1"/></p>
	<p>年龄:<input type="text"  name="age1"/></p>
	<input type="submit" value="提交">
</form>
<h2>map</h2>
<form action="user/add5.do">
	<p>用户名:<input type="text"  name="userName1"/></p>
	<p>密码:<input type="text"  name="password1"/></p>
	<p>年龄:<input type="text"  name="age1"/></p>
	<input type="submit" value="提交">
</form>
<h2>list</h2>
<form action="user/add6.do">
	<p>爱好:
		<input type="checkbox"  name="like" value="篮球"/>
		<input type="checkbox"  name="like" value="足球"/>
		<input type="checkbox"  name="like" value="羽毛球"/>
		<input type="checkbox"  name="like" value="乒乓球"/>
	</p>
	<input type="submit" value="提交">
</form>
<h2>格式化</h2>
<form action="user/add7.do">
	<p>用户名:<input type="text"  name="userName"/></p>
	<p>密码:<input type="text"  name="password"/></p>
	<p>生日:<input type="text"  name="age"/></p>
	<input type="submit" value="提交">
</form>
<h2>格式化</h2>
<form action="user/add8.do">
	<p>用户名:<input type="text"  name="userName"/></p>
	<p>密码:<input type="text"  name="password"/></p>
	<p>生日:<input type="text"  name="age"/></p>
	<input type="submit" value="提交">
</form>
</body>
</html>
package com.sxt.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.ModelAndView;

import com.sun.xml.internal.ws.client.RequestContext;
import com.sxt.pojo.User;

@Controller
@RequestMapping("/user")
public class UserController {

	/**
	 *  简单的数据类型绑定
	 * 	在SpringMVC中,获取请求参数参数,只需要方法中形式参数的名称与请求的数据的name属性值一致,就可以自动的绑定相关参数 且简单数据类型可以自动进行数据转换.
	 * @param userName
	 * @param password
	 * @param age
	 * @return: void
	 */
	@RequestMapping("/add.do")
	public void add(String userName,String password,Integer age) {
		System.out.println(userName);
		System.out.println(password);
		System.out.println(age);
	}
    
	/**
	 *  获取请求的参数,且将其封装到对象中
	 * 		1. 创建对象
	 * 		2.属性注入 根据set方法进行属性注入
	 * @param user
	 * @return: void
	 */
	@RequestMapping("/add2.do")
	public void add(User user)  {
		System.out.println(user);
	}
	
	/**
	 * 请求参数名称和形式参数名称不一致时  可以使用@RequestParam 别名
	 * @param userName
	 * @param password
	 * @param age
	 * @return: void
	 */
	@RequestMapping("/add3.do")
	public void add3(@RequestParam("userName1")String userName,@RequestParam("password1")String password,@RequestParam("age1")Integer age)  {
		System.out.println(userName);
		System.out.println(password);
		System.out.println(age);
	}
	
	/**
	 * name/value  参数别名
	 * required : 是否是必须传递的参数  默认是true
	 * defaultValue : 当这个参数没有的时候的默认值				
	 * @param userName
	 * @param password
	 * @param age
	 * @return: void
	 */
	@RequestMapping("/add4.do")
	public void add4(@RequestParam(name="userName1",required = false,defaultValue = "我是默认值")String userName,@RequestParam("password1")String password,@RequestParam("age1")Integer age)  {
		System.out.println(userName);
		System.out.println(password);
		System.out.println(age);
	}
	/**
	 * 使用Map接收请求参数
	 * @param map
	 * @return: void
	 */
	@RequestMapping("/add5.do")
	public void add4(@RequestParam Map<String,Object> map)  {
		System.out.println(map);
	}
	/**
	 * 接收数组格式的参数
	 * @RequestParam("参数名称")
	 * @param like
	 * @return: void
	 */
	@RequestMapping("/add6.do")
	public void add6(@RequestParam("like")List<String> like)  {
		System.out.println(like);
	}
	/**
	 * 将字符串格式化 时间对象
	 * @param userName
	 * @param password
	 * @param age
	 * @return: void
	 */
	@RequestMapping("/add7.do")
	public void add6(String userName,String password,@DateTimeFormat(pattern = "yyyy-MM-dd")Date age)  {
		System.out.println(userName);
		System.out.println(password);
		System.out.println(age);
	}
	
	@RequestMapping("/add8.do")
	public void add6(User user)  {
		System.out.println(user);
	}
	/**
	 * 内置对象的注入
	 * @return: void
	 */
	@RequestMapping("/httpObj.do")
	public void httpObj(HttpServletRequest req,HttpServletResponse resp,HttpSession session,Model mode) {
		System.out.println(mode);
		System.out.println(req);
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes req1 = (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes();
		System.out.println(req1.getRequest().getServletContext());
		System.out.println(requestAttributes);
		System.out.println(resp);
		System.out.println(session);
	}
}

WebUtil

package com.sxt.util;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

public class WebUtil {
	
	/**
	 * 获取当前请求对象
	 * @return
	 * @return: HttpServletRequest
	 */
	public HttpServletRequest getRequest() {
		ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
		return servletRequestAttributes.getRequest();
	}
	/**
	 * 获取当前Session
	 * @return
	 * @return: HttpSession
	 */
	public HttpSession getSession() {
		return getRequest().getSession();
	}
	/**
	 *  获取当前ServletContext 容器
	 * 	当项目直接启动时,可能需要向ServletContext 设置全局参数
	 * 	如果直接使用 request.getServletContext() 会空指针异常
	 *  所以需要根据WebApplicationContext 获取
	 * @return
	 * @return: ServletContext
	 */
	public ServletContext ServletContext() {
		HttpServletRequest request = getRequest();
		// 若当前请求存在 则直接从当前请求中获取ServletContext
		if(request != null) {
			return request.getServletContext();
		}else {
			// 若不存在则根据WebApplicationContext 获取当前ServletContext
			return ContextLoader.getCurrentWebApplicationContext().getServletContext();
		}
	}
}

编码过滤器

<filter>
  	<filter-name>charset</filter-name>
  	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  	<init-param>
  		<param-name>encoding</param-name>
  		<param-value>UTF-8</param-value>
  	</init-param>
</filter>
<filter-mapping>
  	<filter-name>charset</filter-name>
  	<!-- 此时配置 只过滤 springmvc请求 -->
  	<servlet-name>springmvc</servlet-name>
</filter-mapping>

关于SpringMVC跳转

 SpringMVC中,默认是使用内部转发.

 如果需要使用重定向:redirect:地址

package com.sxt.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("/user")
public class UserController {
	/**
	 * springmvc 默认是使用内部转发
	 * @return
	 * @return: String
	 */
	@RequestMapping("list.do")
	public String list() {
		return "/list.jsp";
	}
    
	/**
	 * 若想使用 重定向 :
	 * 		redirect: 地址
	 * @return
	 * @return: String
	 */
	@RequestMapping("list2.do")
	public String list2() {
		return "redirect:/list.jsp";
	}
	
	@RequestMapping("list3.do")
	public ModelAndView list3() {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("/list.jsp");
		return modelAndView;
	}
	
	@RequestMapping("list4.do")
	public ModelAndView list4() {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("redirect:/list.jsp");
		return modelAndView;
	}
	
}

配置视图解析器

<!-- 配置视图解析器 -->
<!-- 
	配置 SpringMVC视图解析器时 
	 	其前后缀 只对 内部转发生效
 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<!-- 配置视图解析器前缀 -->
	<property name="prefix" value="/WEB-INF/jsp"></property>
	<!-- 配置视图解析器后缀 -->
	<property name="suffix" value=".jsp"></property>
</bean>

springmvc返回json数据

package com.sxt.controller;

import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
public class UserController {
	/**
	 * @Title: list
	 * @author: Mr.T   
	 * @date: 2019年11月26日 下午2:35:12 
	 * @Description: 在springmvc中,方法返回的字符串,默认会当做路径处理.springmvc 默认会解析该路径,
	 * 		因为springmvc 提供了注解 @ResponseBody, 表示该方法返回的是字符,阻止springmvc 当做路径处理
	 * 		默认是用  @ResponseBody 时  中文乱码, 需要设置编码格式  数据格式
	 * @return
	 * @return: String
	 * @throws JSONException 
	 */
	@RequestMapping(value ="/list.do",produces = "text/json;charset=UTF-8" )
	@ResponseBody
	public String  list() throws JSONException {
		System.out.println("==============");
		String msg = "{'name':'张三','age':18}";
		JSONObject json = new JSONObject();
		json.put("name", "张三");
		json.put("age", 18);
		System.out.println(json.toString());
		msg = json.toString();
		return msg;
	}

}

@RestController

  RestController 继承了Controller和ResponseBody,当controller类被RestController修饰时,其下面所有的方法,返回的结果,都会当做字符串输出浏览器. 等价于,在一个类上面定义Controller和ResponseBody.

  一般若用于接口开发,都使用RestController ,若controller不需要进行页面跳转,则可以直接使用RestController。否则(若controller需要页面跳转),只能使用@Controller。

@ResponseBody

  @ResponseBody: 可以作用于方法上和类上面,若作用于方法上,则该方法的返回值,当做字符串输出给客户端.若作用于类上面,则该类中的所有方法的返回值,当做字符串输出给客户端.

springmvc返回json对象

  在springmvc中,默认是使用jackson进行数据解析,进行返回.若返回的结果是一个json对象.可以直接返回.

但是需要导入jackson的相关jar包.

jackson-annotations-2.9.9.jar
jackson-core-2.9.9.jar
jackson-databind-2.9.9.jar
@RequestMapping("/list.do")
public Object list() throws JSONException {
	Map<String,Object> map = new HashMap<String,Object>();
	map.put("name", "韩梅梅");
	return map;
}

@RequestMapping("/list3.do")
public Object list3() throws JSONException {
	User user = new User(1, "韩梅梅", 18);
	return user;
}

文件上传和下载

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="file/upload.do" method="post" enctype="multipart/form-data">
		文本:<input type="text" name="userName" /><br>
		文件:<input type="file" name="fileName" /><br>
			<input type="submit" value="提交" />
	</form>
</body>
</html>

spring-mvc.xml

<!-- 配置解析二进制数据解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>

文件上传

package com.lyang.controller;

import java.io.File;
import java.io.IOException;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
@RequestMapping("/file")
public class FileUploadController {

	@RequestMapping("/upload.do")
	public void upload(@RequestParam("fileName")MultipartFile file,String userName) throws IOException {
		// 获取提交的 input name的属性值
		System.out.println(file.getName());
		// 获取文件真实名称
		System.out.println(file.getOriginalFilename());
		// 获取数据的格式
		System.out.println(file.getContentType());
		// 获取文件的输入流
		System.out.println(file.getInputStream());
		// 获取文件的大小(字节)
		System.out.println(file.getSize());
		// 文件进行保存
		file.transferTo(new File("D:\uploadTest.jpg"));
	}

}

文件下载

package com.lyang.controller;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/file")
public class FileDownloadController {

	@RequestMapping("/download.do")
	public void downLoad(HttpServletResponse resp) {
		// 找到需要被下载的文件
		File file = new File("D:\download.jpg");
		// 创建输入流 读取文件
		FileInputStream fis = null;
		// 输出流
		OutputStream ops = null;
		// 设置数据格式为二进制输数据流,让浏览器不要进行解析
		resp.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
		try {
			// 设置响应头信息 告诉浏览器 文件的相关信息 文件的名称 汉字时 容易出现乱码不识别问题 需要 编码
			String fileName = URLEncoder.encode("下载.jpg", "UTF-8");
			resp.addHeader("Content-Disposition", "form-data;name="img";filename="" + fileName + """);
			// 输入流绑定需要读取的文件!
			fis = new FileInputStream(file);
			// 获取与客户端绑定的数据流
			ops = resp.getOutputStream();
			byte[] data = new byte[1024];
			int len = -1;
			while ((len = fis.read(data)) != -1) {
				// 向客户端输出
				ops.write(data, 0, len);
				ops.flush();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				fis.close();
				ops.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	@RequestMapping("download2.do")
	public ResponseEntity<byte[]> downLoad2(){
		// 找到需要被下载的文件
		File file = new File("D:\download.jpg");
		// 存储文件数据的容器
		byte[] fileByte = null;
		ResponseEntity<byte[]> entity = null;
		try {
			// 将文件一次性读到内存中
			fileByte = FileUtils.readFileToByteArray(file);
			// 创建响应头
			HttpHeaders headers = new HttpHeaders();
			// 设置MediaType  为二进制 避免浏览器解析
			headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
			// 设置文件的名称	 如果名称是中文,需要进行转码
			String fileName = URLEncoder.encode("下载.jpg", "UTF-8");
			headers.setContentDispositionFormData("filename", fileName);
			entity = new ResponseEntity<byte[]>(fileByte, headers, HttpStatus.OK);
		} catch (IOException e) {
			e.printStackTrace();
		} 
		return entity;
	}

}
原文地址:https://www.cnblogs.com/lyang-a/p/12171354.html