提交表单中有文件上传后台如何保证数据的一致性

标签: 交表 中有 文件 | 发表时间:2015-02-02 13:03 | 作者:felix_alone2012
出处:http://www.iteye.com

在公司开发一个后台管理系统时有这样的需求:提交一个表单时,要把表单域内容和上传的文件内容(可以是多个上传文件)一并提交到后台去,并且数据库持久化失败后数据要回滚且文件不应该上传上去,如果文件上传失败同样数据库也要回滚。

 

我的做法是:

1.  Spring MVC的controller只是将参数包装成DTO,提交给service层一并处理文件上传和数据库保存操作。controller中的方法,如:

@RequestMapping("save.do")
	public @ResponseBody String storySave(MultipartHttpServletRequest request, StoryDTO storyDTO, String[] fileName) throws Exception {
		storyDTO.setFiles(request.getFileMap());
		storyDTO.setFileUploadPath(webConfig.getFileUploadPath());
		storyDTO.setFileName(fileName);
		try {
			storyService.processingStory(storyDTO);
		} catch (Exception e) {
			e.printStackTrace();
			return "{\"status\":\"err\"}";
		}
		return "{\"status\":\"ok\"}";
	}

 

 在service里的方法processingStory是被Spring事务管控的,那么这个方法头部就抛出一个Exception异常,且在这个方法里的操作一定是数据持久化操作在先,而文件操作在后。

 

文件操作的潜在的异常也是由processingStory这个方法统一抛出的。service中的处理方法如下:

@Override
	public void processingStory(StoryDTO storyDTO) throws Exception {
		Map<String, MultipartFile> files = storyDTO.getFiles();
		Boolean file1=null,file2=null,file3=null,file4=null;
		String[] fileName = storyDTO.getFileName();
		String fileUploadPath = storyDTO.getFileUploadPath();
		
		String[] pathNames = new String[4];
		InputStream[] ins = new InputStream[4];
		
		for (Entry<String, MultipartFile> entry : files.entrySet()) {
			if("toUpload0".equals(entry.getKey())) {
				file1=true;
				String pathName = fileUploadPath+entry.getValue().getOriginalFilename();
				pathNames[0] = pathName;
				ins[0] = entry.getValue().getInputStream();
				storyDTO.setPosterUrl1(pathName);
			}
			if("toUpload1".equals(entry.getKey())) {
				file2=true;
				String pathName = fileUploadPath+entry.getValue().getOriginalFilename();
				pathNames[1] = pathName;
				ins[1] = entry.getValue().getInputStream();
				storyDTO.setPosterUrl2(pathName);
			}
			if("toUpload2".equals(entry.getKey())) {
				file3=true;
				String pathName = fileUploadPath+entry.getValue().getOriginalFilename();
				pathNames[2] = pathName;
				ins[2] = entry.getValue().getInputStream();
				storyDTO.setPosterUrl3(pathName);
			}
			if("toUpload3".equals(entry.getKey())) {
				file4=true;
				String pathName = fileUploadPath+entry.getValue().getOriginalFilename();
				pathNames[3] = pathName;
				ins[3] = entry.getValue().getInputStream();
				storyDTO.setPosterUrl4(pathName);
			}
		}
		
		if(null == storyDTO.getStoryId()) {
			this.saveStory(storyDTO);
		} else {
			String[] deletePaths = new String[4];
			StoryDTO oldStoryDTO = this.getStoryById(storyDTO.getStoryId());
			if(file1==null && StringUtils.isBlank(fileName[0])){
				deletePaths[0]=oldStoryDTO.getPosterUrl1();
				storyDTO.setPosterEmptyUrl1("Y");
			}
			if(file2==null && StringUtils.isBlank(fileName[1])){
				deletePaths[1]=oldStoryDTO.getPosterUrl2();
				storyDTO.setPosterEmptyUrl2("Y");
			}
			if(file3==null && StringUtils.isBlank(fileName[2])){
				deletePaths[2]=oldStoryDTO.getPosterUrl3();
				storyDTO.setPosterEmptyUrl3("Y");
			}
			if(file4==null && StringUtils.isBlank(fileName[3])){
				deletePaths[3]=oldStoryDTO.getPosterUrl4();
				storyDTO.setPosterEmptyUrl4("Y");
			}
			StoryUpdateDTO updateDTO = new StoryUpdateDTO();
			BeanUtils.copyProperties(updateDTO, storyDTO);
			updateDTO.setUpdateStoryId(storyDTO.getStoryId());
			this.updateStory(updateDTO);
			
			for (String path : deletePaths) {
				if(StringUtils.isNotBlank(path)) {
					FileOprUtils.deleteFile(path);
				}
			}
		}
		
		for(int i = 0; i < pathNames.length; i++) {
			FileOprUtils.copyFileToServerPath(pathNames[i], ins[i]);
		}
	}

 

 最后是Spring的声明式事务配置:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="rollbackOnCommitFailure" value="true" />
		<property name="globalRollbackOnParticipationFailure" value="true" />
	</bean>
	
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="*" rollback-for="Exception" propagation="REQUIRED" />
		</tx:attributes>
	</tx:advice>
	<aop:config>
		<aop:advisor advice-ref="txAdvice"
			pointcut="execution(* com.focoon.ds..service.*.*(..))" />
	</aop:config>

 

 注意需要使用rollback-for属性明确指出抛出哪种异常需要回滚

 



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [交表 中有 文件] 推荐:

提交表单中有文件上传后台如何保证数据的一致性

- - 企业架构 - ITeye博客
在公司开发一个后台管理系统时有这样的需求:提交一个表单时,要把表单域内容和上传的文件内容(可以是多个上传文件)一并提交到后台去,并且数据库持久化失败后数据要回滚且文件不应该上传上去,如果文件上传失败同样数据库也要回滚.  Spring MVC的controller只是将参数包装成DTO,提交给service层一并处理文件上传和数据库保存操作.

python 下载文件

- Eric - python相关的python 教程和python 下载你可以在老王python里寻觅
之前给大家分享的python 多线程抓取网页,我觉的大家看了以后,应该会对python 抓取网页有个很好的认识,不过这个只能用python 来抓取到网页的源代码,如果你想用做python 下载文件的话,上面的可能就不适合你了,最近我在用python 做文件下载的时候就遇到这个问题了,不过最终得以解决,为了让大家以后碰过这个问题有更好的解决办法,我把代码发出来:.

Ext文件系统

- Haides - 博客园-首页原创精华区
  虽然从Ext2到Ext4,找数据的方式发生了变化,但是,磁盘的布局还是非常相似的. 其实这个东西也不需要变化,因为现在也没什么特别巧妙的方式,而且磁盘的吞吐量、效率的瓶颈也不在这里. 当然,这里排除那些根据自身文件特点设计的数据库,毕竟还是为了支持通用文件.   Boot在第一个块,放的应该是引导程序,超级块就放在了第二个块上,如果不是可以在mount的时候通过参数sb来设置.

Linux 文件结构

- Shiina Luce - OSMSG
想了解 Linux 文件系统树形结构,却又不愿翻阅 FHS 的朋友,可以参考 skill2die4 制作的这张简图. 此图算是 FHS 的图形化版本,简要的说明了 Linux 系统中各个目录的用途及层级关系,适合初学者使用参考. 不过其中较新的如 /run 目录并未在其中出现. 做为参考,这是 Fedora 16 Beta i686 上的文件结构:.

多文件上传

- - BlogJava-首页技术区
多文件上传 jquery的插件. 使用的方法  导入 jquery.js 及 jquery.MultiFile.js ,. 方式一: 后台是文件数组  .  private File[] upload; // 与jsp表单中的名称对应. 在 form 中加入 即可.

Zookeeper配置文件

- - 学着站在巨人的肩膀上
复制conf/zoo_sample.cfg文件为conf/zoo.cfg,修改其中的数据目录. tickTime:这个时间作为Zookeeper服务器之间或者服务器与客户端之间维护心跳的时间,时间单位毫秒. initLimit:选举leader的初始延时. 由于服务器启动加载数据需要一定的时间(尤其是配置数据非常多),因此在选举 Leader后立即同步数据前需要一定的时间来完成初始化.

读取 calss文件

- - zzm
System.out.println("解析失败. int length = 0; // 长度,字节,B. double kblength = 0.0D; // 长度,千字节,KB. System.out.println("文件大小(字节):" + length + "\n文件大小(KB):" + kblength);.

Flume监听文件夹中的文件变化_并把文件下沉到hdfs

- - 行业应用 - ITeye博客
摘要: 1、采集目录到HDFS 采集需求:某服务器的某特定目录下,会不断产生新的文件,每当有新文件出现,就需要把文件采集到HDFS中去 根据需求,首先定义以下3大要素 采集源,即source——监控文件目录 : spooldir 下沉目标,即sink——HDFS文件系统 : hdfs sink source和sink之间的传递通道——channel,可用file chann.

Marlin: Elementary 文件管理器

- 加州旅客 - LinuxTOY
如果您喜好 OS X Finder 风格的文件管理器,Marlin 必然适合您. Marlin 文件管理器作为 Elementary OS 项目的一部分由 ammonkey 开发. Marlin 拥有如同 Finder 的列表视图:. 以及小小的选择 + 号和单击启动模式:. 现在 Marlin 测试版本的 PPA 仓库已经上线,在 Ubuntu 11.04 中安装,请进行:.