图片的存储与回显,从前端写到后台,我所用的一套处理方式,记录下,路过的小猿,少踩坑。
先说下我的业务背景吧,我在前端所要封装的信息主要是一个完整的类信息,类下包括所要传递的图片以及一些别的属性,没错,我这是将属性与图片一起封装传递的。工程的后台架构是springBoot+ssm,前台架构是angularJs,jquery等,本来想着angularJs的双向绑定想着省事点,没想到因为这个在图片存储这一块踩了一路的坑。
存储思路:将所有信息包括图片封装为一个FormData对象,传递formdata至后台处理,后台将图片存储到指定路径,返回一个文件名,将文件名保存至数据库,然后通过springBoot的一些优雅的方式让图片在页面显示。
html部分代码
<table>
<tr>
<td>姓名<span style="color:red">*</span></td>
<td><input placeholder="姓名" id="tch_name" name="tch_name" ng-model="tch.tch_name"></td>
</tr>
<tr>
<td>介绍</td>
<td><textarea rows="4" name="tch_desc" ng-model="tch.tch_desc"></textarea></td>
</tr>
<tr>
<td>形象照</td>
<td><input type="file" id="tch_picFile" name="tch_picFile" accept="image/png, image/jpeg" file-model="tch.tch_pic" /></td>
</tr>
</table>
<div class="modal-footer">
<button ng-click="addTch()">保存</button>
</div>
这里的图片输入框我没有用angularJs的方式去处理,不为别的,纯粹是菜。包括后面的获取input输入框的基本信息与图片信息,我也没用angularJs处理,还是因为足够纯粹。
js部分代码
处理input输入框,通过jquery获取输入框的信息,封装为FormData对象。突然发现这个对象用来前后交互真是非常友好,特别是对于我这种前端比较纯粹的后台。
<script>
$scope.addTch = function () {
//数据处理
var formData = new FormData();
formData.append("tch_picFile",$('input[name=tch_picFile]')[0].files[0]); //获取图片信息,并封装到formdata对象里
formData.append("tch_name",$("input[name='tch_name']").val()); //获取姓名并封装
formData.append("tch_desc",$("textarea[name='tch_desc']").val()); //获取介绍并封装
$http({
url : "http://localhost:8486/teacher/addTch", //后台接口的url
method : 'POST', //请求方式为post,至于get的处理方式,水平不够省略
data : formData, //formdata作为参数传递
headers: {'Content-Type': undefined}, // 注意 ,此处不声明数据传递的格式,让浏览器自己选择
transformRequest: angular.identity //注意 ,之前纯粹得我就是因为这个选项没填,死了好久,,好久,作为angular的请求方式是填这个,如果用的是jquery的请求就不是这样了
}).success(function (response) { //成功回调函数
if(response.flag){
alert('保存成功');
window.location.reload();
}else{
alert(response.info);
}
});
}
</script>
这里需要注意以下几点
- 此处采用的是angular的请求方式,如果你用的是别的框架,可以在我的参考链接里看看。
- 此处未采用form标签封装input,所以也没有在form标签里添加这个属性 enctype=“multipart/form-data”,如果你用form标签,好像也可以不添加,浏览器应该能识别你所要传输的信息
- headers: {‘Content-Type’: undefined} ,文本类型不声明,浏览器智能匹配
- transformRequest: angular.identity,这个参数,在我使用的图片传输里,是最坑我的,务必声明,如果不声明,你再F12的控制台是看不到传递的图片信息,因为没传递。。。
- method : ‘POST’, data : formData, 如果你用的是post的请求方式,在angularJs里,传递参数要用data表示,get的话是用params,不然,可能会传递失败
SpringMvc部分代码
@CrossOrigin //跨域处理
@RestController
@RequestMapping(value = "teacher")
public class TeacherController {
//文件保存地址
@Value("${img.upload-path}")
private String uploadPicturePath;
@Autowired
private TeacherService teacherService;
/**
* 新增讲师
* @param tch_picFile
* @param tch
* @return
*/
@RequestMapping(value = "addTch",method = RequestMethod.POST)
public ResultInfo addTch(@RequestParam(value = "tch_picFile",required = false)MultipartFile tch_picFile,Teacher tch){
//定义用于接收所传图片的文件名
String filename = null;
//定义流对象接收前端所传的图片信息
InputStream ism = null;
try{
if (tch_picFile != null && tch_picFile.getOriginalFilename() != null){
//获取前端所传图片的名字,用于判断文件后缀
filename = tch_picFile.getOriginalFilename();
//获取图片流资源
ism = tch_picFile.getInputStream();
//通过工具类处理图片并返回文件名
String pic_name = PictureUtil.picUtil(ism, filename, uploadPicturePath);
//判断巩工具类返回的路径是否为空,不为空则保存到stu对象中
tch.setTch_pic(pic_name);
}
//避免产生undefined
if (tch.getTch_desc().equals("undefined")){
tch.setTch_desc("");
}
//保存
teacherService.addTch(tch);
} catch (Exception e) {
e.printStackTrace();
return new ResultInfo(false,"讲师添加失败");
}
return new ResultInfo(true,"讲师添加成功");
}
}
这里需要注意的地方
- @CrossOrigin springBoot对于跨域的解决措施之一
- @RequestParam(value = “tch_picFile”,required = false)MultipartFile tch_picFile 获取前台传过来的图片信息,这里的value跟在前台formdata封装的key要一致,不然要空指针,同时也要用MultipartFile 去接受文件,,,别的信息会因为你的formdata设置的key与你的bean里的属性名一样,所以会被自动封装为你指定的bean对象
图片工具类部分代码
public class PictureUtil {
/**
* 保存图片,并返回绝对路径
* @param stu_pic 图片资源
* @param pic_name 图片名用于判断后缀
* @param filePath 保存路径
* @return 将返回的文件名存进数据库
*/
public static String picUtil(InputStream stu_pic,String pic_name,String filePath){
String fileName = null;
FileInputStream fileInputStream = null;
try{
fileName = getFileName(pic_name);
fileInputStream = (FileInputStream) stu_pic;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath + File.separator + fileName));
byte[] bs = new byte[1024];
int len;
while ((len = fileInputStream.read(bs)) != -1) {
bos.write(bs, 0, len);
}
bos.flush();
bos.close();
}catch (Exception e){
e.printStackTrace();
}
return fileName;
}
/**
* 生成图片名跟后缀
* @param file_name
* @return
*/
public static String getFileName(String file_name){
Date date = new Date();
long time = date.getTime();
String pic_name = time+"";
if (file_name.contains(".png")){
pic_name += ".png";
}
if (file_name.contains(".jpg")){
pic_name += ".jpg";
}
return pic_name;
}
}
后台对图片处理的思路,本来是想保存绝对路径到数据库,然后返回前台二进制,再在前台显示,,,但是在无意中突然发现,springBoot一个很优雅的特性,就是,你可以指定本地的一个路径作为资源路径,该文件下的所有文件能被页面html直接识别,img的src属性能够直接访问到,,,这样就很舒服了啊,所以仅保存文件名到数据库,便于图片的回显。这一点是在一个博客中学习到的,博客链接文末会有,很nice的以为兄台。
以上就是图片从前台到后台的一个大致过程,写的比较慌乱
接下来说说图片回显的一个大致思路:
首先通过配置类实现本地路径的资源化,让它能被前端页面访问到,然后在controller里面引用在这个资源路径通过picutil将图片存储在这个路径下,这样之后你只要返回给前台文件名,再进行一些简单处理,img的src标签就能直接访问到了,具体如下
springBoot配置类部分代码
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Created by carlson chis on 2019/1/10 0010.
* Describe:
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//在D:/imgdemo/下如果有一张 Excalibar.jpg的图片,那么:
//【1】访问:http://localhost:8080/imgs/Excalibar.jpg 可以访问到
//【2】html 中 <img src="imgs/Excalibar.jpg">
registry.addResourceHandler("/imgs/**").addResourceLocations("file:D:/imgdemo/");
}
}
这里还是非常感谢那位优雅的博客主:
https://blog.youkuaiyun.com/qq_30447263/article/details/81085171
springMvc部分代码
/**
* 获取图片
* @param tch_id
* @return
*/
@RequestMapping(value = "findPicByTchId")
public String findPicByTchId(int tch_id){
return teacherService.findPicByTchId(tch_id);
}
这里就返回了图片的文件名,例如1547193961615.png
js部分代码
//获取讲师照片
$scope.findPicByTchId=function(tch_id){
$http.get('http://localhost:8486/teacher/findPicByTchId?tch_id='+tch_id).success(function(response){
var pic_url = "http://localhost:8486/imgs/"+response;
$("#tch_pic").attr("src", pic_url); //给img赋值,显示图片
}
});
}
html部分代码
<div>
<img id="tch_pic" src="" height="300px" width="260px">
</div>
<button type="button" class=" btn btn-sm" data-toggle="modal" data-target="#editTchPicModel" ng-click = "findPicByTchId(tch.tch_id)">详情</button>
大概的过程就是这样子,如果有问题,请指正呀。。。。
参考链接
https://blog.youkuaiyun.com/xllily_11/article/details/52330280
https://www.cnblogs.com/yangtoude/p/jquery-ajax-formdata-upload.html
https://blog.youkuaiyun.com/qq_41669724/article/details/80748952
https://blog.youkuaiyun.com/wei389083222/article/details/51289704
https://blog.youkuaiyun.com/qq_30447263/article/details/81085171
1168





