1.引入插件及页面中的写法

图片裁剪插件

canvas转换为image插件

1.1.引入样式

1
<link rel="stylesheet" href="../../static/lib/simple-crop-master/template-1.css">

1.2.引入相关依赖和组件源代码

1
2
3
4
5
6
7
<!--引入图片裁剪插件-->
<script src="../../static/lib/simple-crop-master/prefix-umd.js"></script>
<script src="../../static/lib/simple-crop-master/exif.js"></script>
<script src="../../static/lib/simple-crop-master/transformation-matrix.js"></script>
<script src="../../static/lib/simple-crop-master/index.js"></script>
<!--引入canvas转换为image插件-->
<script src="../../static/js/Canvas2Image.js"></script>

1.3.初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
var simpleCrop = new SimpleCrop({
title: '选择头像', //标题
// src: 'src/mian/resource/static/images/514.png', //裁剪图片地址
size: { //裁剪尺寸
width: 600,
height: 600
},
visible: false, //打开页面时不显示裁剪弹窗
cropSizePercent: 0.65, //裁剪框显示比例
scaleSlider: true, //是否显示滑动控制条
maxScale: 3, //最大缩放倍数
borderWidth: 1, //裁剪框边框宽度
funcBtns: ['close', 'crop', 'upload'], //功能按钮配置
borderColor: "#fff", //裁剪框边框颜色
coverColor: 'rgba(0,0,0,.5)', //裁剪框遮罩颜色
startAngle: -360, //旋转刻度盘开始角度
endAngle: 360, //旋转刻度盘结束角度
cropCallback: function ($resultCanvas) { //图片裁剪完成回调函数
/*
* 原作者将裁剪后的图片追加到body上;
* 而我需要其base64值转换为图片存储到硬盘上,
* 再将地址复制给user.avatar,所以注释掉
*
* console.log('cropCallback');
* $resultCanvas.style.marginRight = '10px';
* $resultCanvas.style.width = '50%';
* document.body.appendChild($resultCanvas);
*/
/*
* 测试Canvas2Image插件
* document.body.appendChild(Canvas2Image.convertToJPEG($resultCanvas, 600, 600));
*/
/*
* 在表单中设置了一个隐藏域<input id="avatar" type="hidden" name="avatar">,
* 为其赋值裁剪后的图片的base64值
*/
$('#avatar').val(Canvas2Image.convertToJPEG($resultCanvas, 600, 600).src);
},
uploadCallback: function (src) { //上传裁剪图片成功回调函数
// 注意:此处的src是原图片的base64值
// console.log('uploadCallback ' + src);
},
closeCallback: function () { //关闭组件回调函数
// console.log('closeCallback');
}
});

1.4.选取裁剪图片

1
<input id="upload" type="file" accept="image/png,image/jpeg">
1
2
3
4
5
6
7
8
var $upload = document.querySelector('#upload');
$upload.addEventListener('change', function (evt) {
var files = evt.target.files;
if (files.length > 0) {
simpleCrop.show(files[0]); //显示
}
$upload.value = ''; //清空 input value属性
});

1.5.更新组件参数

1
2
3
4
5
6
<!--原readme的写法-->
<button id="update">组件更新</button>
<!--我加了一些自己的样式,参考即可-->
<button type="reset" id="update" class="ui violet button j-padded-z-6 j-text-thin-500">
重新裁剪
</button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var $update = document.querySelector('#update');
$update.addEventListener('click', function () {
simpleCrop.updateBox({ //更新裁剪框尺寸和显示比例
cropSizePercent: 0.7,
size: {
width: 600,
height: 600,
}
});
simpleCrop.initBoxBorder({ //更新裁剪框边框样式
borderColor: "#0BFF00",
});
simpleCrop.show(); //显示
});

2.Controller的写法

表单提交到这个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@PostMapping("/setting")
public String setting(User user, HttpServletRequest request){
//在初始化中,已经给隐藏域中的id为avatar的input赋过值了(line:37)
String base64Avatar = user.getAvatar();
//base64头像非空时,存储头像并将路径赋值给user.avatar
if (base64Avatar != null && !"".equals(base64Avatar)) {
//剪切后的头像的文件名
String avatarOriginalFilename = System.currentTimeMillis() + ".jpg";
/*
* 注意:使用springboot时,内置的tomcat的request.getServletContext().getRealPath("/")
* 得到的不是当前项目的路径,可以使用new File(BLOG_STATIC_IMAGES_PATH).getAbsoluteFile()来得到
*
* BLOG_STATIC_IMAGES_PATH =
* linux : "WEB-INF/classes/static/images/"
* 本地win10的IDEA开发 : "src/main/resources/static/images"
*/
//剪切后头像的绝对路径
String avatarAbsolutePath = request.getServletContext().getRealPath("/") + BLOG_STATIC_IMAGES_PATH + avatarOriginalFilename;
try {
/*
* 在此处 http://sharehoo.cn/topic/detail/414 找到
* 解决IllegalArgumentException: Illegal base64 character 3a异常的方法:
*
* 前端将文件转换后,结构为这样:
* data:image/png;base64,iVBORw0AAAAA...
* 需要将没用的字符串剪切掉:data:image/png;base64,从","号开始切割,只留数据部分即可。
*/
// Base64解码
if (base64Avatar.contains(",")) {
String encodedImg = base64Avatar.split(",")[1];
byte[] decodedImg = Base64.getDecoder().decode(encodedImg.getBytes(StandardCharsets.UTF_8));
/*
* 在此处 https://blog.csdn.net/qq_36964933/article/details/98474021 找到
* 解决将byte[]转换为MultipartFile对象的方法
*/
//将base64编码转换为的字节数组decodedImg,再转换为MultipartFile对象
MultipartFile avatarFile = new MockMultipartFile(MediaType.APPLICATION_OCTET_STREAM_VALUE, new ByteArrayInputStream(decodedImg));
//写文件
avatarFile.transferTo(new File(avatarAbsolutePath));
//给当前用户设置剪切后的头像
user.setAvatar("/images/" + avatarOriginalFilename);
}
} catch (Exception e) {
throw new RuntimeException("文件上传失败");
}
}
//重定向到返回页面的get方法
return "redirect:/admin/setting/" + userService.saveUser(user).getId();
}

返回页面的get方法:

1
2
3
4
5
6
7
@GetMapping("/setting/{userId}")
public String setting(@PathVariable Long userId, Model model, HttpSession session) {
User user = userService.getUser(userId);
model.addAttribute("user", user);
session.setAttribute("user", user);
return "admin/setting";
}