飞道的博客

SpringMVC(十一):SpringMVC文件上传中要解决的问题

324人阅读  评论(0)

文章目录

SpringMVC文件上传中要解决的问题

一、中文文件名编码问题

二、文件位置存储问题

三、文件名冲突问题

四、控制文件类型和大小 

五、上传图片回显问题

六、进度条问题

七、单独准备文件存储服务器

八、保存完整player信息进入数据库


SpringMVC文件上传中要解决的问题

一、中文文件名编码问题

通过过滤器解决

二、文件位置存储问题

放在当前项目下,作为静态资源,这样可以通过URL访问。


  
  1. package com.lanson.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.ResponseBody;
  5. import org.springframework.web.multipart.MultipartFile;
  6. import javax.servlet.http.HttpServletRequest;
  7. import java.io.File;
  8. import java.io.IOException;
  9. /**
  10. * @Author: Lansonli
  11. * @Description: MircoMessage:Mark_7001
  12. */
  13. @Controller
  14. public class FileUploadController {
  15. @ResponseBody
  16. @RequestMapping("fileUpload.do")
  17. public String fileUpload (MultipartFile headPhoto, HttpServletRequest req) throws IOException {
  18. // 指定文件存储目录为我们项目部署环境下的upload目录
  19. String realPath = req.getServletContext().getRealPath( "/upload");
  20. File dir = new File(realPath);
  21. // 如果不存在则创建目录
  22. if(!dir.exists()){
  23. dir.mkdirs();
  24. }
  25. // 获取文件名
  26. String originalFilename = headPhoto.getOriginalFilename();
  27. // 文件存储位置
  28. File file = new File(dir,originalFilename);
  29. // 文件保存
  30. headPhoto.transferTo(file);
  31. return "OK";
  32. }
  33. }

在SpringMVC中配置静态资源放行

<mvc:resources mapping="/upload/**" location="/upload/"></mvc:resources>

 

三、文件名冲突问题

使用UUID对文件名进行重命名。

 


  
  1. package com.lanson.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.ResponseBody;
  5. import org.springframework.web.multipart.MultipartFile;
  6. import javax.servlet.http.HttpServletRequest;
  7. import java.io.File;
  8. import java.io.IOException;
  9. import java.util.UUID;
  10. /**
  11. * @Author: Lansonli
  12. * @Description: MircoMessage:Mark_7001
  13. */
  14. @Controller
  15. public class FileUploadController {
  16. @ResponseBody
  17. @RequestMapping("fileUpload.do")
  18. public String fileUpload (MultipartFile headPhoto, HttpServletRequest req) throws IOException {
  19. // 指定文件存储目录为我们项目部署环境下的upload目录
  20. String realPath = req.getServletContext().getRealPath( "/upload");
  21. File dir = new File(realPath);
  22. // 如果不存在则创建目录
  23. if(!dir.exists()){
  24. dir.mkdirs();
  25. }
  26. // 获取文件名
  27. String originalFilename = headPhoto.getOriginalFilename();
  28. // 避免文件名冲突,使用UUID替换文件名
  29. String uuid = UUID.randomUUID().toString();
  30. // 获取拓展名
  31. String extendsName = originalFilename.substring(originalFilename.lastIndexOf( "."));
  32. // 新的文件名
  33. String newFileName=uuid.concat(extendsName);
  34. // 文件存储位置
  35. File file = new File(dir,newFileName);
  36. // 文件保存
  37. headPhoto.transferTo(file);
  38. return "OK";
  39. }
  40. }

四、控制文件类型和大小 


  
  1. package com.lanson.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.ResponseBody;
  5. import org.springframework.web.multipart.MultipartFile;
  6. import javax.servlet.http.HttpServletRequest;
  7. import java.io.File;
  8. import java.io.IOException;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. import java.util.UUID;
  12. /**
  13. * @Author: Lansonli
  14. * @Description: MircoMessage:Mark_7001
  15. */
  16. @Controller
  17. public class FileUploadController {
  18. @ResponseBody
  19. @RequestMapping("fileUpload.do")
  20. public Map<String,String> fileUpload (MultipartFile headPhoto, HttpServletRequest req) throws IOException {
  21. Map<String,String> map= new HashMap<>();
  22. // 控制文件大小
  23. if(headPhoto.getSize()> 1024* 1024* 5){
  24. map.put( "message", "文件大小不能超过5M");
  25. return map;
  26. }
  27. // 指定文件存储目录为我们项目部署环境下的upload目录
  28. String realPath = req.getServletContext().getRealPath( "/upload");
  29. File dir = new File(realPath);
  30. // 如果不存在则创建目录
  31. if(!dir.exists()){
  32. dir.mkdirs();
  33. }
  34. // 获取文件名
  35. String originalFilename = headPhoto.getOriginalFilename();
  36. // 避免文件名冲突,使用UUID替换文件名
  37. String uuid = UUID.randomUUID().toString();
  38. // 获取拓展名
  39. String extendsName = originalFilename.substring(originalFilename.lastIndexOf( "."));
  40. // 控制文件类型
  41. if(!extendsName.equals( ".jpg")){
  42. map.put( "message", "文件类型必须是.jpg");
  43. return map;
  44. }
  45. // 新的文件名
  46. String newFileName=uuid.concat(extendsName);
  47. // 文件存储位置
  48. File file = new File(dir,newFileName);
  49. // 文件保存
  50. headPhoto.transferTo(file);
  51. // 上传成功之后,把文件的名字和文件的类型返回给浏览器
  52. map.put( "message", "上传成功");
  53. map.put( "newFileName", newFileName);
  54. map.put( "filetype", headPhoto.getContentType());
  55. return map;
  56. }
  57. }

通过文件上传解析组件控制。

但是会出现异常,后期可以可以配置一个异常解析器解决。


  
  1. <!--文件上传解析组件
  2. id必须为multipartResolver
  3. springmvc默认使用该id找该组件
  4. -->
  5. <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
  6. <!--设置文件大小-->
  7. <property name="maxUploadSizePerFile" value="10"> </property>
  8. </bean>

五、上传图片回显问题

后天已经将图片的文件名响应给浏览器。

前端代码


  
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Title </title>
  5. <script type="text/javascript" src="js/jquery.min.js"> </script>
  6. <script type="text/javascript">
  7. $( function( ){
  8. $( "#uploadFile"). click( function( ){
  9. // 获取要上传的文件
  10. var photoFile =$( "#photo")[ 0]. files[ 0]
  11. if(photoFile== undefined){
  12. alert( "您还未选中文件")
  13. return;
  14. }
  15. // 将文件装入FormData对象
  16. var formData = new FormData();
  17. formData. append( "headPhoto",photoFile)
  18. // ajax向后台发送文件
  19. $. ajax({
  20. type: "post",
  21. data:formData,
  22. url: "fileUpload.do",
  23. processData: false,
  24. contentType: false,
  25. success: function( result){
  26. // 接收后台响应的信息
  27. alert(result. message)
  28. // 图片回显
  29. $( "#headImg"). attr( "src", "upload/"+result. newFileName);
  30. }
  31. })
  32. })
  33. })
  34. </script>
  35. </head>
  36. <body>
  37. <form action="addPlayer" method="get">
  38. <p>账号 <input type="text" name="name"> </p>
  39. <p>密码 <input type="text" name="password"> </p>
  40. <p>昵称 <input type="text" name="nickname"> </p>
  41. <p>头像:
  42. <br/>
  43. <input id="photo" type="file">
  44. <br/>
  45. <img id="headImg" style="width: 200px;height: 200px" alt="你还未上传图片">
  46. <br/>
  47. <a id="uploadFile" href="javascript:void(0)">立即上传 </a>
  48. </p>
  49. <p> <input type="submit" value="注册"> </p>
  50. </form>
  51. </body>
  52. </html>

六、进度条问题


  
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Title </title>
  5. <style>
  6. .progress {
  7. width: 200px;
  8. height: 10px;
  9. border: 1px solid #ccc;
  10. border-radius: 10px;
  11. margin: 10px 0px;
  12. overflow: hidden;
  13. }
  14. /* 初始状态设置进度条宽度为0px */
  15. .progress > div {
  16. width: 0px;
  17. height: 100%;
  18. background-color: yellowgreen;
  19. transition: all . 3s ease;
  20. }
  21. </style>
  22. <script type="text/javascript" src="js/jquery.min.js"> </script>
  23. <script type="text/javascript">
  24. $( function( ){
  25. $( "#uploadFile"). click( function( ){
  26. // 获取要上传的文件
  27. var photoFile =$( "#photo")[ 0]. files[ 0]
  28. if(photoFile== undefined){
  29. alert( "您还未选中文件")
  30. return;
  31. }
  32. // 将文件装入FormData对象
  33. var formData = new FormData();
  34. formData. append( "headPhoto",photoFile)
  35. // ajax向后台发送文件
  36. $. ajax({
  37. type: "post",
  38. data:formData,
  39. url: "fileUpload.do",
  40. processData: false,
  41. contentType: false,
  42. success: function( result){
  43. // 接收后台响应的信息
  44. alert(result. message)
  45. // 图片回显
  46. $( "#headImg"). attr( "src", "upload/"+result. newFileName);
  47. },
  48. xhr: function( ) {
  49. var xhr = new XMLHttpRequest();
  50. //使用XMLHttpRequest.upload监听上传过程,注册progress事件,打印回调函数中的event事件
  51. xhr. upload. addEventListener( 'progress', function ( e) {
  52. //loaded代表上传了多少
  53. //total代表总数为多少
  54. var progressRate = (e. loaded / e. total) * 100 + '%';
  55. //通过设置进度条的宽度达到效果
  56. $( '.progress > div'). css( 'width', progressRate);
  57. })
  58. return xhr;
  59. }
  60. })
  61. })
  62. })
  63. </script>
  64. </head>
  65. <body>
  66. <form action="addPlayer" method="get">
  67. <p>账号 <input type="text" name="name"> </p>
  68. <p>密码 <input type="text" name="password"> </p>
  69. <p>昵称 <input type="text" name="nickname"> </p>
  70. <p>头像:
  71. <br/>
  72. <input id="photo" type="file">
  73. <%--图片回显--%>
  74. <br/>
  75. <img id="headImg" style="width: 200px;height: 200px" alt="你还未上传图片">
  76. <br/>
  77. <%--进度条--%>
  78. <div class="progress">
  79. <div> </div>
  80. </div>
  81. <a id="uploadFile" href="javascript:void(0)">立即上传 </a>
  82. </p>
  83. <p> <input type="submit" value="注册"> </p>
  84. </form>
  85. </body>
  86. </html>

七、单独准备文件存储服务器

分服务器上传作用

  • 数据库服务器:运行我们的数据库
  • 缓存和消息服务器:负责处理大并发访问的缓存和消息
  • 文件服务器:负责存储用户上传文件的服务器。
  • 应用服务器:负责部署我们的应用

在实际开发中,我们会有很多处理不同功能的服务器。(注意:此处说的不是服务器集群)

总结:分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。

分服务器工作示意图

 

单独解压一个Tomcat作为文件服务器

设置远程服务器端口号 

 

远程服务器中设置非只读

 

webapps下创建一个upload目录

 

启动测试

项目中导入依赖


  
  1. <dependency>
  2. <groupId>com.sun.jersey </groupId>
  3. <artifactId>jersey-client </artifactId>
  4. <version>1.19 </version>
  5. </dependency>

controller代码


  
  1. package com.lanson.controller;
  2. import com.sun.jersey.api.client.Client;
  3. import com.sun.jersey.api.client.WebResource;
  4. import org.springframework.stereotype.Controller;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.ResponseBody;
  7. import org.springframework.web.multipart.MultipartFile;
  8. import javax.servlet.http.HttpServletRequest;
  9. import java.io.File;
  10. import java.io.IOException;
  11. import java.util.HashMap;
  12. import java.util.Map;
  13. import java.util.UUID;
  14. /**
  15. * @Author: Lansonli
  16. * @Description: MircoMessage:Mark_7001
  17. */
  18. @Controller
  19. public class FileUploadController {
  20. // 文件存储位置
  21. private final static String FILESERVER= "http://192.168.8.109:8090/upload/";
  22. @ResponseBody
  23. @RequestMapping("fileUpload.do")
  24. public Map<String,String> fileUpload (MultipartFile headPhoto, HttpServletRequest req) throws IOException {
  25. Map<String,String> map= new HashMap<>();
  26. // 获取文件名
  27. String originalFilename = headPhoto.getOriginalFilename();
  28. // 避免文件名冲突,使用UUID替换文件名
  29. String uuid = UUID.randomUUID().toString();
  30. // 获取拓展名
  31. String extendsName = originalFilename.substring(originalFilename.lastIndexOf( "."));
  32. // 新的文件名
  33. String newFileName=uuid.concat(extendsName);
  34. // 创建 sun公司提供的jersey包中的client对象
  35. Client client=Client.create();
  36. WebResource resource = client.resource(FILESERVER + newFileName);
  37. // 文件保存到另一个服务器上去了
  38. resource.put(String.class, headPhoto.getBytes());
  39. // 上传成功之后,把文件的名字和文件的类型返回给浏览器
  40. map.put( "message", "上传成功");
  41. map.put( "newFileName",newFileName);
  42. map.put( "filetype", headPhoto.getContentType());
  43. return map;
  44. }
  45. }

页面代码


  
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Title </title>
  5. <style>
  6. .progress {
  7. width: 200px;
  8. height: 10px;
  9. border: 1px solid #ccc;
  10. border-radius: 10px;
  11. margin: 10px 0px;
  12. overflow: hidden;
  13. }
  14. /* 初始状态设置进度条宽度为0px */
  15. .progress > div {
  16. width: 0px;
  17. height: 100%;
  18. background-color: yellowgreen;
  19. transition: all . 3s ease;
  20. }
  21. </style>
  22. <script type="text/javascript" src="js/jquery.min.js"> </script>
  23. <script type="text/javascript">
  24. $( function( ){
  25. $( "#uploadFile"). click( function( ){
  26. // 获取要上传的文件
  27. var photoFile =$( "#photo")[ 0]. files[ 0]
  28. if(photoFile== undefined){
  29. alert( "您还未选中文件")
  30. return;
  31. }
  32. // 将文件装入FormData对象
  33. var formData = new FormData();
  34. formData. append( "headPhoto",photoFile)
  35. // ajax向后台发送文件
  36. $. ajax({
  37. type: "post",
  38. data:formData,
  39. url: "fileUpload.do",
  40. processData: false,
  41. contentType: false,
  42. success: function( result){
  43. // 接收后台响应的信息
  44. alert(result. message)
  45. // 图片回显
  46. $( "#headImg"). attr( "src", "http://192.168.8.109:8090/upload/"+result. newFileName);
  47. },
  48. xhr: function( ) {
  49. var xhr = new XMLHttpRequest();
  50. //使用XMLHttpRequest.upload监听上传过程,注册progress事件,打印回调函数中的event事件
  51. xhr. upload. addEventListener( 'progress', function ( e) {
  52. //loaded代表上传了多少
  53. //total代表总数为多少
  54. var progressRate = (e. loaded / e. total) * 100 + '%';
  55. //通过设置进度条的宽度达到效果
  56. $( '.progress > div'). css( 'width', progressRate);
  57. })
  58. return xhr;
  59. }
  60. })
  61. })
  62. })
  63. </script>
  64. </head>
  65. <body>
  66. <form action="addPlayer" method="get">
  67. <p>账号 <input type="text" name="name"> </p>
  68. <p>密码 <input type="text" name="password"> </p>
  69. <p>昵称 <input type="text" name="nickname"> </p>
  70. <p>头像:
  71. <br/>
  72. <input id="photo" type="file">
  73. <%--图片回显--%>
  74. <br/>
  75. <img id="headImg" style="width: 200px;height: 200px" alt="你还未上传图片">
  76. <br/>
  77. <%--进度条--%>
  78. <div class="progress">
  79. <div> </div>
  80. </div>
  81. <a id="uploadFile" href="javascript:void(0)">立即上传 </a>
  82. </p>
  83. <p> <input type="submit" value="注册"> </p>
  84. </form>
  85. </body>
  86. </html>

八、保存完整player信息进入数据库

index.html


  
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Title </title>
  5. <style>
  6. .progress {
  7. width: 200px;
  8. height: 10px;
  9. border: 1px solid #ccc;
  10. border-radius: 10px;
  11. margin: 10px 0px;
  12. overflow: hidden;
  13. }
  14. /* 初始状态设置进度条宽度为0px */
  15. .progress > div {
  16. width: 0px;
  17. height: 100%;
  18. background-color: yellowgreen;
  19. transition: all . 3s ease;
  20. }
  21. </style>
  22. <script type="text/javascript" src="js/jquery.min.js"> </script>
  23. <script type="text/javascript">
  24. $( function( ){
  25. $( "#uploadFile"). click( function( ){
  26. // 获取要上传的文件
  27. var photoFile =$( "#photo")[ 0]. files[ 0]
  28. if(photoFile== undefined){
  29. alert( "您还未选中文件")
  30. return;
  31. }
  32. // 将文件装入FormData对象
  33. var formData = new FormData();
  34. formData. append( "headPhoto",photoFile)
  35. // ajax向后台发送文件
  36. $. ajax({
  37. type: "post",
  38. data:formData,
  39. url: "fileUpload.do",
  40. processData: false,
  41. contentType: false,
  42. success: function( result){
  43. // 接收后台响应的信息
  44. alert(result. message)
  45. // 图片回显
  46. $( "#headImg"). attr( "src", "http://192.168.8.109:8090/upload/"+result. newFileName);
  47. // 将文件类型和文件名放入form表单
  48. $( "#photoInput"). val(result. newFileName)
  49. $( "#filetypeInput"). val(result. filetype)
  50. },
  51. xhr: function( ) {
  52. var xhr = new XMLHttpRequest();
  53. //使用XMLHttpRequest.upload监听上传过程,注册progress事件,打印回调函数中的event事件
  54. xhr. upload. addEventListener( 'progress', function ( e) {
  55. //loaded代表上传了多少
  56. //total代表总数为多少
  57. var progressRate = (e. loaded / e. total) * 100 + '%';
  58. //通过设置进度条的宽度达到效果
  59. $( '.progress > div'). css( 'width', progressRate);
  60. })
  61. return xhr;
  62. }
  63. })
  64. })
  65. })
  66. </script>
  67. </head>
  68. <body>
  69. <form action="addPlayer" method="get">
  70. <p>账号 <input type="text" name="name"> </p>
  71. <p>密码 <input type="text" name="password"> </p>
  72. <p>昵称 <input type="text" name="nickname"> </p>
  73. <p>头像:
  74. <br/>
  75. <input id="photo" type="file">
  76. <%--图片回显--%>
  77. <br/>
  78. <img id="headImg" style="width: 200px;height: 200px" alt="你还未上传图片">
  79. <br/>
  80. <%--进度条--%>
  81. <div class="progress">
  82. <div> </div>
  83. </div>
  84. <a id="uploadFile" href="javascript:void(0)">立即上传 </a>
  85. <%--使用隐藏的输入框存储文件名称和文件类型--%>
  86. <input id="photoInput" type="hidden" name="photo" >
  87. <input id="filetypeInput" type="hidden" name="filetype">
  88. </p>
  89. <p> <input type="submit" value="注册"> </p>
  90. </form>
  91. </body>
  92. </html>

FileUploadController代码

见上一步

playerController代码


  
  1. package com.lanson.controller;
  2. import com.lanson.pojo.Player;
  3. import com.lanson.service.PlayerService;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Controller;
  6. import org.springframework.web.bind.annotation.RequestMapping;
  7. /**
  8. * @Author: Lansonli
  9. * @Description: MircoMessage:Mark_7001
  10. */
  11. @Controller
  12. public class PlayerController {
  13. @Autowired
  14. private PlayerService playerService;
  15. @RequestMapping("addPlayer")
  16. public String addPlayer (Player player){
  17. // 调用服务层方法,将数据保存进入数据库
  18. playerService.addPlayer(player);
  19. // 页面跳转至player信息展示页
  20. return "redirect:/showPlayer.jsp";
  21. }
  22. }

Service层代码


  
  1. package com.lanson.service.impl;
  2. import com.lanson.mapper.PlayerMapper;
  3. import com.lanson.pojo.Player;
  4. import com.lanson.service.PlayerService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Service;
  7. /**
  8. * @Author: Lansonli
  9. * @Description: MircoMessage:Mark_7001
  10. */
  11. @Service
  12. public class PlayerServiceImpl implements PlayerService {
  13. @Autowired
  14. private PlayerMapper playerMapper;
  15. @Override
  16. public boolean addPlayer (Player player) {
  17. return playerMapper.addPlayer(player)> 0;
  18. }
  19. }

mapper代码


  
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.lanson.mapper.PlayerMapper">
  6. <insert id="addPlayer">
  7. insert into player values(DEFAULT ,#{name},#{password},#{nickname},#{photo},#{filetype})
  8. </insert>
  9. </mapper>

  • 📢博客主页:https://lansonli.blog.csdn.net
  • 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
  • 📢本文由 Lansonli 原创,首发于 CSDN博客🙉
  • 📢停下休息的时候不要忘了别人还在奔跑,希望大家抓紧时间学习,全力奔赴更美好的生活✨

转载:https://blog.csdn.net/xiaoweite1/article/details/128645143
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场