商家后台-商品录入【商品图片上传】
1.1 需求分析
在商品录入界面实现多图片上传
当用户点击新建按钮,弹出上传窗口
- 实现思路分析:
- AngularJS图片上传(异步请求上传图片)。
- SpringMVC图片上传(配置文件上传依赖jar包、配置文件上传解析器、控制器接收上传的文件)
- FastDFS图片文件器(配置客户端依赖jar包、配置文件、编写上传服务器代码)
- 商品图片上传:
-- 需求分析
Angularjs图片上传(异步请求上传图片)
-- 异步请求代码
/** 文件上传方法 */
this.uploadFile = function(){
/** 创建表单对象 */
var formData = new FormData(); // html5 FormData
/** 追加需要上传的文件 */
formData.append("file", file.files[0]);
/** 发送异步请求上传文件 */
return $http({
method : 'post', // 请求方式
url : "/upload", // 请求URL
data : formData, // 表单数据
headers : {'Content-Type' : undefined}, // 请求头
transformRequest : angular.identity // 转换对象
});
}; SpringMVC接收上传的文件(配置文件上传依赖jar、
配置文件上传解析器、控制器接收上传的文件)
FastDFS图片服务器(配置客户端依赖jar、
配置文件、编写上传服务器代码)注意:开启图片服务器
1.2 图片上传
1.2.1 上传服务
sunny-shop-web/src/main/webapp/js/controller/baseService.js中的uploadFile()方法:
app.service("baseService", function($http){
......
/** 文件上传方法 */
this.uploadFile = function(){
/** 创建表单对象 */
var formData = new FormData();
/** 追加需要上传的文件 */
formData.append("file", file.files[0]);
/** 发送异步请求上传文件 */
return $http({
method : 'post', // 请求方式
url : "/upload", // 请求URL
data : formData, // 表单数据
headers : {'Content-Type' : undefined}, // 请求头
transformRequest : angular.identity // 转换对象
});
};
});
- angularJS对于post和get请求默认的Context-Type header是application/json。通过设置‘Content-Type’: undefined,这样浏览器会帮我们把Content-Type设置为 multipart/form-data.
- 设置 transformRequest : angular.identity,angularjs transformRequest function 将序列化表单对象中的文件为二进制数据.
1.2.2 前端代码
goods_edit.html,修改图片上传窗口,调用上传方法,回显上传图片(300行左右)
<table class="table table-bordered table-striped">
<tr>
<td>颜色</td>
<td><input class="form-control"
ng-model="picEntity.color" placeholder="颜色"></td>
</tr>
<tr>
<td>商品图片</td>
<td>
<table>
<tr>
<td><input type="file" id="file"/>
<button class="btn btn-primary"
ng-click="uploadFile()"
type="button">上传</button>
</td>
<td><img src="{{picEntity.url}}"
width="200px" height="200px"></td>
</tr>
</table>
</td>
</tr>
</table>
sunny-shop-web/src/main/webapp/js/controller/goodsController.js中编写代码
/**上传图片 */
$scope.uploadFile = function(){
baseService.uploadFile().then(function(response) {
/** 如果上传成功,取出url */
if(response.data.status == 200){
/** 设置图片访问地址 */
$scope.picEntity.url = response.data.url;
}else{
alert("上传失败!");
}
});
};
goods_edit.html修改新建按钮,绑定点击事件(122行),用于初始化对象(清空数据)
<div class="btn-group">
<button type="button" class="btn btn-default" title="新建"
data-target="#uploadModal" data-toggle="modal"
ng-click="picEntity={}">
<i class="fa fa-file-o"></i> 新建
</button>
</div>
1.3 后端代码
1.3.1 配置依赖
sunny-shop-web/pom.xml,配置引入依赖
<!-- commons-fileupload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> </dependency> <!-- fastdfs-client --> <dependency> <groupId>org.csource</groupId> <artifactId>fastdfs-client</artifactId> </dependency>
1.3.2 配置文件上传解析器
sunny-shop-web/src/main/resources/springmvc.xml配置文件上传解析器
<!-- 配置文件上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置文件上传默认编码 -->
<property name="defaultEncoding" value="UTF-8"/>
<!-- 设置文件上传大小 2MB: 2*1024*1024 -->
<property name="maxUploadSize" value="2097152"/>
</bean>
1.3.3 控制器层、fastdfs_client.conf配置文件、application.properties配置文件
(1)在sunny-shop-web/src/main/resources目录下创建fastdfs_client.conf
(2) 在sunny-shop-web/src/main/resources/目录下,新建application.properties,并添加属性
(3)在sunny-shop-web/src/main/resources/springmvc.xml配置加载application.properties
<!-- 加载属性文件 -->
<context:property-placeholder location="classpath:application.properties"/>
控制器层:在sunny-shop-web/src/main/java/com.sunny.shop.controller包下创建UploadController.java
- 这时需要思考从前端传过来什么格式的数据,用什么去封装的问题?
响应数据:图片的URL、状态码{url: ' ' , status: 200}
所以采用Map<String,Object>集合封装
此时在参数上使用@RequestParam注解
@RestController public class UploadController { /** 注入文件服务器访问地址 */ @Value("${fileServerUrl}") private String fileServerUrl; /** 文件上传 */ @PostMapping("/upload") public Map<String, Object>
upload(@RequestParam("file")MultipartFile multipartFile) { Map<String, Object> data = new HashMap<>(); data.put("status", 500); try { /** 加载配置文件,产生该文件绝对路径 */ String conf_filename = this.getClass() .getResource("/fastdfs_client.conf").getPath(); /** 初始化客户端全局对象 */ ClientGlobal.init(conf_filename); /** 创建存储客户端对象 */ StorageClient storageClient = new StorageClient();
/** 获取原文件名 */
String originalFilename =
multipartFile.getOriginalFilename();
/** 上传文件到FastDFS服务器 */
String[] arr = storageClient
.upload_file(multipartFile.getBytes(),
FilenameUtils.getExtension(originalFilename), null);
/** 拼接返回的 url 和 ip 地址,拼装成完整的 url */
StringBuilder url = new StringBuilder(fileServerUrl);
for (String str : arr){
url.append("/" + str);
}
data.put("status", 200);
data.put("url", url.toString());
} catch (Exception e) {
e.printStackTrace();
}
return data;
}
}
2.1 图片列表(包含了图片数据的封装)
- 点击保存按钮,需要将图片显示在页面上面。
- 图片列表:
-- 商品图片保存到tb_goods_desc 的 item_images 列
[{"color":"金色",
"url":"http://image.pinyougou.com/jd/wKgMg1qtKEOATL9nAAFti6upbx4132.jpg"},
{"color":"深空灰色",
"url":"http://image.pinyougou.com/jd/wKgMg1qtKHmAFxj7AAFZsBqChgk725.jpg"},
{"color":"银色",
"url":"http://image.pinyougou.com/jd/wKgMg1qtKJyAHQ9sAAFuOBobu-A759.jpg"}]
$scope.goods.goodsDesc.itemImages = [];
goods_edit.html修改上传窗口的保存按钮,绑定点击事件
<button class="btn btn-success" data-dismiss="modal"
ng-click="addPic()"
aria-hidden="true">保存</button>
sunny-shop-web/src/main/webapp/js/controller/goodsController.js增加方法
/** 定义数据存储结构 */
$scope.goods = { goodsDesc : { itemImages : []}};
/** 添加图片到数组 */
$scope.addPic = function(){
$scope.goods.goodsDesc.itemImages.push($scope.picEntity);
};
goods_edit.html迭代图片列表(140行左右)
<tr ng-repeat="pic in goods.goodsDesc.itemImages">
<td>{{pic.color}}</td>
<td><img alt="" src="{{pic.url}}"
width="100px" height="100px"></td>
<td>
<button type="button" class="btn btn-default" title="删除">
<i class="fa fa-trash-o"></i> 删除
</button>
</td>
</tr>
2.2 移除图片
goods_edit.html修改列表中的删除按钮,绑定点击事件
<button type="button" class="btn btn-default" title="删除"
ng-click="removePic($index)">
<i class="fa fa-trash-o"></i> 删除</button>
sunny-shop-web/src/main/webapp/js/controller/goodsController.js增加代码
/** 数组中移除图片 */
$scope.removePic = function(index){
$scope.goods.goodsDesc.itemImages.splice(index, 1);
};