用户发表文章(Post),在xheditor中写文字和上传图片,交叉进行,图片文件上传到了服务器,图片的名称,url,大小等信息在上传的同时需要单独保存在一张表里。
因此在上一篇的UploadController中除了做上传图片这事之外,还要向Attachment记录图片信息。修改代码如下:
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
50
51
52
53
54
55
56
57
58
59
60
61
62
|
@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字符串中几个参数的作用::
(1)err:当这个值不为空时,xheditor会在JSP中弹出一个上传失败的对话框并显示err的内容
(2)url: 最终拼凑的可在浏览器中访问的http图片地址,xheditor直接根据这个值在editor中显示图片
(3)localname:这个值不是必须的,一般用来存储图片的名字,是url中的最后部分(也可以不是,比如我url中的图片名字是用时间戳命名的,而这里localname是图片本身的名字)
(4)id:这个值不是必须的,它代表图片在attachment表中的id,回传到JSP,当发表文章做进一步的处理
这张表Attachment和Post是多对一关系,Attachment表中有一个post_id,问题是:保存图片信息的时候, post_id还不存在(用户还没有提交Post呢),
怎么办呢?
我们可以在每次上传时插入一条没有post_id的图片记录,等到用户真正发表文章的时候,批量更新这些attachment的post_id,相关代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@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,加入了如下配置:
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
|
<!-- 解决@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日志中看出加这个配置的作用
加之前
[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如下:
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
|
<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表单元素如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<
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
>
|
最终的效果如下: