场景
点击添加--选择照片--点击保存--保存到数据库路径--页面展示。
实现
前面实现照片上传可以用其他实现,这里是用BJUI来实现。
需要给后台action传过去base64Str。
添加页面代码:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<c:set var="ctx" value="${pageContext.request.contextPath}" />
<script type="text/javascript" src="${ctx}/resources/js/cropper/cropper.js"></script>
<link rel="stylesheet" type="text/css" href="${ctx}/resources/js/cropper/cropper.css" />
<script type="text/javascript"
src="${ctx}/resources/BJUI/plugins/kindeditor_4.1.10/kindeditor.js"></script>
<script type="text/javascript">
window.CKEDITOR_BASEPATH = '${ctx}/resources/js/ckeditor/';
</script>
<style type="text/css">
#user-photo {
width:150px;
height:150px;
margin-top: 10px;
margin-left: 115px;
}
#photo {
max-width:100%;
max-height:350px;
}
.img-preview-box {
text-align: center;
}
.img-preview-box > div {
display: inline-block;;
margin-right: 10px;
}
.img-preview {
overflow: hidden;
}
.img-preview-box .img-preview-lg {
width: 150px;
height: 150px;
}
.img-preview-box .img-preview-md {
width: 100px;
height: 100px;
}
.img-preview-box .img-preview-sm {
width: 50px;
height: 50px;
border-radius: 50%;
}
.modal-backdrop{
z-index:0;!important
}
</style>
<script type="text/javascript"
src="${ctx}/resources/js/ckeditor/ckeditor.js"></script>
<script type="text/javascript">
var editor = null;
KindEditor.create(
'textarea[name="content"]',
{
uploadJson : '${ctx}/bus/pushMessageAction/doSaveImage',
fillDescAfterUploadImage : false, //上传图片成功后转到属性页,为false则直接插入图片[设为true方便自定义函数(X_afterSelect)]
items : [ 'source', '|', 'undo', 'redo', '|', 'preview',
'print', 'template', 'cut', 'copy', 'paste',
'plainpaste', 'wordpaste', '|', 'justifyleft',
'justifycenter', 'justifyright', 'justifyfull',
'insertorderedlist', 'insertunorderedlist', 'indent',
'outdent', 'subscript', 'superscript', 'clearhtml',
'quickformat', 'selectall', '|', 'fullscreen', '/',
'formatblock', 'fontname', 'fontsize', '|',
'forecolor', 'hilitecolor', 'bold', 'italic',
'underline', 'strikethrough', 'lineheight',
'removeformat', '|', 'table', 'hr', 'image' ],
//allowFileManager : true,
height : "400px",
width :"80%",
allowImageUpload : true,
autoHeightMode : true,
afterCreate : function() {
this.loadPlugin('autoheight');
},
afterBlur : function() {
this.sync();
} //Kindeditor下获取文本框信息
})
</script>
<div class="bjui-pageContent">
<form action="${ctx}/bus/pushMessageAction/doSave"
class="ajaxForm" data-toggle="validate" enctype="multipart/form-data">
<input type="hidden" name="op" id="j_dialog_op"
value="${param.op}${op}"> <input type="hidden" name="id"
id="j_dialog_id" value="${message.id}">
<input
type="hidden" name="recordTime" id="recordTime" value="<fmt:formatDate value="${message.recordTime}" pattern="yyyy-MM-dd HH:mm:ss" />">
<c:if test="${!empty role}">
<input type="hidden" name="status" id="j_dialog_op"
value="${message.status}">
</c:if>
<table class="table table-condensed table-hover">
<tbody>
<tr>
<td colspan="2" align="center" valign="middle"><h4>${title}</h4></td>
</tr>
<tr style="height: 30px;">
<td><label for="name" class="control-label x90">消息标题:</label>
<input class="" id="title" type="text" name="title"
value="${message.title}" data-rule="标题:required;" /></td>
</tr>
<tr style="height: 30px;">
<td><label for="name" class="control-label x90">消息类型:</label>
<select data-toggle="selectpicker" name="messageType">
<c:forEach items= "${codeList}" var="cc">
<option value="${cc.codeValue }" ${message.messageType == cc.codeValue?"selected='selected'":""}>${cc.codeName}
</option>
</c:forEach>
</select>
</tr>
<tr style="height: 30px;" id="content_tr">
<td colspan="2" align="center"><label for="description" class="float:left;">发现内容:</label>
<textarea name="content" id="content" class="j-content" rows="4"
cols="58" data-toggle="kindeditor" data-minheight="500"
style="width: 100%">
${message.content}
</textarea></td>
</tr>
<tr style="height: 30px;" id="vary">
<td><label for="name" class="control-label x90">主题图片:</label>
<input class="" id="themeImageUrl" type="text"
name="themeImageUrl" readonly="readonly"
value="${message.themeImageUrl}" />
<button data-target="#changeModal" data-toggle="modal" type="button">选择文件</button>
<!-- <input type="file" name="file" id="input" accept="image/*" style="width: 40%;">
<div id="hidfail"></div> -->
<!-- <div class="row">
<div class="pic">
<img src="" id="photo">
</div>
<div class="col-sm-2">
<button class="btn btn-primary" onclick="crop()" type="button">裁剪图片</button>
<button class="btn btn-primary" onclick="cropfail()" type="button">取消裁剪</button>
<div>
<br/>
<p>
结果:
</p>
<input type="hidden" name="base64Str" id="imgBase64Url">
<img src="" alt="裁剪结果" id="result" >
</div>
</div>
</div> -->
<div class="user-photo-box">
<img id="user-photo" src="">
<input type="hidden" name="base64Str" id="imgBase64Url">
</div>
</div>
<div class="modal fade" id="changeModal" tabindex="1050" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title text-primary">
<i class="fa fa-pencil"></i>
裁剪图片
</h4>
</div>
<div class="modal-body">
<p class="tip-info text-center">
未选择图片
</p>
<div class="img-container hidden">
<img src="" alt="" id="photo">
</div>
<div class="img-preview-box hidden">
<hr>
<span>150*150:</span>
<div class="img-preview img-preview-lg">
</div>
<!-- <span>100*100:</span>
<div class="img-preview img-preview-md">
</div>
<span>30*30:</span>
<div class="img-preview img-preview-sm">
</div> -->
</div>
</div>
<div class="modal-footer">
<label class="btn btn-danger pull-left" for="photoInput">
<input type="file" class="sr-only" id="photoInput" accept="image/*">
<span>打开图片</span>
</label>
<button class="btn btn-primary disabled" disabled="true" onclick="sendPhoto()" type="button">提交</button>
<!-- <button class="btn btn-close" aria-hidden="true" data-dismiss="modal">取消</button> -->
</div>
</div>
</div>
</div>
</td>
</tr>
<tr style="height: 30px;">
<td colspan="2"><label for="description"
class="control-label x90">备注:</label> <textarea name="remark"
id="remark" rows="5" cols="58">${message.remark}</textarea></td>
</tr>
</tbody>
</table>
</form>
</div>
<script type="text/javascript">
var initCropperInModal = function(img, input, modal){
var $image = img;
var $inputImage = input;
var $modal = modal;
var options = {
aspectRatio: 1, // 纵横比
viewMode: 2,
preview: '.img-preview' // 预览图的class名
};
// 模态框隐藏后需要保存的数据对象
var saveData = {};
var URL = window.URL || window.webkitURL;
var blobURL;
$modal.on('show.bs.modal',function () {
// 如果打开模态框时没有选择文件就点击“打开图片”按钮
if(!$inputImage.val()){
$inputImage.click();
}
}).on('shown.bs.modal', function () {
// 重新创建
$image.cropper( $.extend(options, {
ready: function () {
// 当剪切界面就绪后,恢复数据
if(saveData.canvasData){
$image.cropper('setCanvasData', saveData.canvasData);
$image.cropper('setCropBoxData', saveData.cropBoxData);
}
}
}));
}).on('hidden.bs.modal', function () {
// 保存相关数据
saveData.cropBoxData = $image.cropper('getCropBoxData');
saveData.canvasData = $image.cropper('getCanvasData');
// 销毁并将图片保存在img标签
$image.cropper('destroy').attr('src',blobURL);
});
if (URL) {
$inputImage.change(function() {
var files = this.files;
var file;
if (!$image.data('cropper')) {
return;
}
if (files && files.length) {
file = files[0];
if (/^image\/\w+$/.test(file.type)) {
if(blobURL) {
URL.revokeObjectURL(blobURL);
}
blobURL = URL.createObjectURL(file);
// 重置cropper,将图像替换
$image.cropper('reset').cropper('replace', blobURL);
// 选择文件后,显示和隐藏相关内容
$('.img-container').removeClass('hidden');
$('.img-preview-box').removeClass('hidden');
$('#changeModal .disabled').removeAttr('disabled').removeClass('disabled');
$('#changeModal .tip-info').addClass('hidden');
} else {
window.alert('请选择一个图像文件!');
}
}
});
} else {
$inputImage.prop('disabled', true).addClass('disabled');
}
}
var sendPhoto = function(){
var url=$('#photo').cropper('getCroppedCanvas',{
width:300,
height:300
}).toDataURL('image');
$('#user-photo').attr('src',url);
$("#imgBase64Url").val(url);
console.log("url=="+url);
$('#changeModal').modal('hide');
};
/* var sendPhoto = function(){
$('#photo').cropper('getCroppedCanvas',{
width:300,
height:300
}).toBlob(function(blob){
// 转化为blob后更改src属性,隐藏模态框
$('#user-photo').attr('src',URL.createObjectURL(blob));
$('#changeModal').modal('hide');
});
} */
$(function(){
initCropperInModal($('#photo'),$('#photoInput'),$('#changeModal'));
});
</script>
<div class="bjui-pageFooter">
<ul>
<li><button type="button" class="btn-close" data-icon="close">关闭</button></li>
<li><button type="submit" class="btn-default" data-icon="save">保存</button></li>
</ul>
</div>
实现效果
点击上传照片
裁剪之前
点击保存后提交到后台action
@Description("信息保存")
@ResponseBody
@RequestMapping(value = "/doSave")
public Map<String, Object> doSave(TbMessage entity, String op, String base64Str, String[] itemIdStr) {
Map<String, Object> jsonResult = null;
String msg = "";
try {
if (base64Str.length()!= 0) {
String result = ImageUtil.getInstance().baseUploadImg(
Constants.UPLOAD_IMG_MESSAGE, base64Str);
entity.setThemeImageUrl((String) result);
}
String tabid = tabid(ModelAndViewConstants.MESSAGE_SYS_ID);
Date now = new Date();
ShiroUser currentUser = (ShiroUser) SecurityUtils.getSubject().getPrincipal();
// 添加
if (null == op || ModelAndViewConstants.OPERATION_VALUE_ADD.equals(op)) {
entity.setStatus("0");
entity.setRecordTime(now);
entity.setUserId(currentUser.getUserId());
this.service.insert(entity);
} else {// 编辑
entity.setModifyDate(now);
this.service.updateByPrimaryKey(entity);
DataSourceHolder.setDataSource("demoDs");//切换云端数据源
this.service.updateByPrimaryKey(entity);
}
Integer statusCode = 200;
String Msg = "消息信息保存成功";
jsonResult = JsonResult.jsonReturn(statusCode, Msg, tabid);
return jsonResult;
} catch (Exception e) {
msg = "接口调用异常";
jsonResult = JsonResult.jsonWsReturn(1, msg, e.getMessage());
LogService.getInstance(this).error("保存消息信息失败" + e.getMessage());
String mg = "保存消息信息失败:" + e.getMessage();
jsonResult = JsonResult.jsonReturnErr(mg);
return jsonResult;
}
}
前台控件给后台action传过来base64Str。
工具类ImageUtil
public String baseUploadImg(String dir, String base64) {
OutputStream out = null;
String path = null;
String filePath = null;
try {
if ("".equals(base64)) {
return null;
}
base64 = base64.substring(base64.indexOf(",") + 1);
byte[] b = Base64.decode(base64);
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {// 调整异常数据
b[i] += 256;
}
}
String fileName = dir + "_" + new Random().nextInt()
+ DateConvert.formatDateToString(new Date(), DateStyle.YYYYMMDDHHMMSS) + ".png";
path = dir + File.separator + fileName;
// 存储路径
String dirPath = ResourceUtil.getUploadImageRelativeRoot2() + dir;
filePath = ResourceUtil.getUploadImageRelativeRoot2() + path;
// 创建新的文件
boolean resultDir = FileUtil.makedir(dirPath);
if (resultDir == true) {
LogService.getInstance(this).debug(filePath);
File file = new File(filePath);
out = new FileOutputStream(file);
out.write(b);
out.flush();
out.close();
} else {
LogService.getInstance(this).error("建立文件夹" + dir + "失败,完整路径为:dirPath");
}
} catch (Exception e) {
e.printStackTrace();
}
return ResourceUtil.getUploadImgRelativeRoot()+path;
}
在存储路径这个地方又调用ResourceUtil下的getUploadImageRelativeRoot2()
来获取存储图片的相对路径。
public static final String getUploadImageRelativeRoot2() {
return System.getProperty("catalina.home")+File.separator+"webapps"+File.separator+"img"+File.separator;
}
jsp页面代码
<img src="${ctx}/{{html themeImageUrl}}">
效果
记得要配置Tomcat下的server.xml路径映射。