用户发表文章(Post),在xheditor中写文字和上传图片,交叉进行,图片文件上传到了服务器,图片的名称,url,大小等信息在上传的同时须要单独保存在一张表里。 javascript
所以在上一篇的UploadController中除了作上传图片这事以外,还要向Attachment记录图片信息。修改代码以下: css
@Controller @RequestMapping("/upload") public class UploadController { private static final Log logger = LogFactory.getLog(UploadController.class); @Autowired private AttachmentService attachmentService; @RequestMapping(value = "/image", method = RequestMethod.POST) @ResponseBody public String image(HttpServletRequest request, HttpSession session, @RequestParam("filedata") MultipartFile file) throws Exception { // 将图片按日期分开存放,方便管理 final String prefix = "upload/images/" + DateUtil.getFormatedDate("yyyy/MM_dd"); // 存放到web根目录下,若是日期目录不存在,则建立, // 注意 request.getRealPath("/") 已经标记为不推荐使用了. final String realPath = session.getServletContext().getRealPath(prefix); logger.info(realPath); File dir = new File(realPath); if (!dir.exists()) { dir.mkdirs(); } // 如下是真正的上传部分 String error = ""; // 取得原文件名 String originName = file.getOriginalFilename(); // 取得文件后缀 String fileExt = originName.substring(originName.lastIndexOf(".") + 1); // 按时间戳生成图片文件名 String picture = DateUtil.getFormatedDate("yyyyMMddHHmmss") + "." + fileExt; Attachment attachment = new Attachment(); try { IOUtils.copy(file.getInputStream(), new FileOutputStream(new File(dir, picture))); //向attachment表中插入一条post_id为空的图片记录 attachment.setDownloadCount(0); attachment.setSize((int) file.getSize()); attachment.setUrl(prefix + "/" + picture); attachment = attachmentService.createAttachment(attachment); } catch (Exception e) { logger.error("error:", e); error = e.getMessage(); } String http = "http://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath(); String url = http + "/" + prefix + "/" + picture; //注意这里的格式(见xheditor文档) //{'err':'',msg:{'url':'XXX/upload/images/2012/11_11/20121111015039.jpg','localname':'个人头像.jpg','id':'63'}} String json = String.format("{'err':'%s',msg:{'url':'%s','localname':'%s','id':'%s'}}", error, url, originName, attachment.getId()); return json; } }
稍微解释一下xheditor json字符串中几个参数的做用:: html
(1)err:当这个值不为空时,xheditor会在JSP中弹出一个上传失败的对话框并显示err的内容
(2)url: 最终拼凑的可在浏览器中访问的http图片地址,xheditor直接根据这个值在editor中显示图片
(3)localname:这个值不是必须的,通常用来存储图片的名字,是url中的最后部分(也能够不是,好比我url中的图片名字是用时间戳命名的,而这里localname是图片自己的名字)
(4)id:这个值不是必须的,它表明图片在attachment表中的id,回传到JSP,当发表文章作进一步的处理 html5
这张表Attachment和Post是多对一关系,Attachment表中有一个post_id,问题是:保存图片信息的时候, post_id还不存在(用户尚未提交Post呢), java
怎么办呢? web
咱们能够在每次上传时插入一条没有post_id的图片记录,等到用户真正发表文章的时候,批量更新这些attachment的post_id,相关代码以下: spring
@Override public void updateAttachmentsWithPostId(List<Attachment> attchments, Long postId) { List<Object[]> batchArgs = new ArrayList<Object[]>(); if (attchments != null) { for (Attachment attachment : attchments) { Object[] args = new Object[] { postId, attachment.getId() }; batchArgs.add(args); } } String sql = "update cms_attachment set post_id = ? where id=?"; jdbcTemplate.batchUpdate(sql, batchArgs); }
其间解决了一个@ResponseBody乱码问题(json字符串中的localname为中文时回传到JSP中是乱码)
在这里找到了解决办法:http://www.oschina.net/code/snippet_103691_11482,加入了以下配置: sql
<!-- 解决@ResponseBody乱码问题, 须要在annotation-driven以前而且spring版本须要3.1.2以上 --> <!--Spring3.1推荐使用RequestMappingHandlerAdapter --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" /> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>text/plain;charset=UTF-8</value> </list> </property> </bean> <bean class="org.springframework.http.converter.ResourceHttpMessageConverter" /> <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" /> <bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" /> <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" /> </list> </property> </bean>
咱们能够从spring日志中看出加这个配置的做用 json
加以前 数组
[DEBUG] Written [{'err':'',msg:
{'url':'http://localhost:9080/spring/upload/images/2012/11_11/20121111011413.jpg','localname':'个人头
像.jpg','id':'50'}}] as "text/html" using
[org.springframework.http.converter.StringHttpMessageConverter@93d9c7]
加以后:
[DEBUG] Written [{'err':'',msg:{'url':'http://localhost:9080/spring/upload/images/2012/11_11/20121111015039.jpg','localname':'个人头像.jpg','id':'63'}}] as "text/plain;charset=UTF-8" using [org.springframework.http.converter.StringHttpMessageConverter@1fdec30]
前台部分,相关的JS以下:
<script type="text/javascript"> //图片预览 function previewImage(x){ $('#preview').attr("src", "${ctx}/" + $(x).find("option:selected").val()); } $(document).ready(function() { //初始化xhEditor编辑器插件 $('#content').xheditor({ tools : 'full', skin : 'default', upImgUrl : "${ctx}/upload/image", upImgExt : "jpg,jpeg,png,gif", html5Upload : false, onUpload : insertUpload }); //图片上传回调函数 function insertUpload(arrMsg) { //xheditor返回的arrMsg是一个Object数组 var msg = arrMsg[0]; //(1)其中url插入到编辑器,这样xheditor才能正常显示图片 var url = msg.url; $("#content").append(url); //如下步骤不是必须的 //(2)将attachment_id保存到checkbox中,发表文章时根据这些attachment_id去更新图片的post_id var id = msg.id; $("#imagesDiv").append("<input type='checkbox' name='attachments' checked='checked' onclick='return false;' value='"+id+"''/><br>"); //(3)图片的名字放到下拉列表,用户从下拉列表 中选择图片作为Post的主题图片 var localname = msg.localname; var urlWithoutHttp = url.substring(url.indexOf("/upload")+1); $("#topicImageUrl").append("<option value='"+urlWithoutHttp+"'>" + localname + "</option>"); } //聚焦第一个输入框 $("#name").focus(); //为inputForm注册validate函数 $("#inputForm").validate(); }); </script>
相关的form表单元素以下:
<div class="control-group"> <label class="control-label" for="content">内容:</label> <div class="controls"> <sf:textarea path="content" rows="15" cssClass="span10"/> </div> <div class="controls" id="imagesDiv" style="display:none"> </div> </div> <div class="control-group"> <label class="control-label" for="topicImageUrl">主题图片:</label> <div class="controls"> <sf:select path="topicImageUrl" onchange='previewImage(this)'> <sf:option value="">Please select</sf:option> </sf:select> </div> </div> <div class="control-group"> <label class="control-label" for="hit">图片预览:</label> <div class="controls"> <img id="preview" src="" border="0" width="200" height="200" /> </div> </div>
最终的效果以下: