`

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

 
阅读更多

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

 

我的做法是:

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属性明确指出抛出哪种异常需要回滚

 

分享到:
评论

相关推荐

    Servlet的5种方式实现表单提交(注册小功能),后台获取表单数据实例

    如果表单中包含文件上传,我们可以使用@MultipartConfig注解来处理文件上传。这种方法可以简化文件上传的处理过程,并且提高上传的安全性。 实体类的设计 在处理表单数据时,我们需要设计一个实体类来存储表单数据...

    php无刷新提交表单

    - **文件上传**:用户上传文件后,无需整个页面重新加载即可看到上传状态或结果。 - **评论提交**:用户提交评论后,评论立即显示在页面上而无需刷新整个页面。 - **表单验证**:实时验证表单输入,及时反馈错误信息...

    绿色表单提交商务网页模板

    【绿色表单提交商务网页模板】是一个专门设计用于商务场景的网页模板,其核心功能是提供一个用户友好的...开发者可以将这些文件上传到服务器,然后根据需要进行配置和调整,以创建一个符合自身需求的商务表单提交网页。

    改造matrix admin模版后台 基础表单(六)

    可以通过修改模板的SCSS或CSS文件,调整表单元素的颜色、边框、间距等属性,同时注意保持与模板其他部分的视觉一致性。 7. **表单布局优化**:根据表单内容的复杂性,可能需要调整布局,如使用栅格系统进行分栏布局...

    C#多文件上传实例代码

    在ASP.NET 3.5框架下,多文件上传是一个常见的需求,特别是在开发涉及用户交互、数据提交和资源管理的Web应用程序时。以下是对"C#多文件上传实例代码"这一主题的详细解释: **多文件上传的基本概念:** 多文件上传...

    后台内容的输入

    2. **数据验证**:前端验证可以提供即时反馈,但后端验证是必需的,以确保数据的安全性和一致性。这包括对必填字段的检查、长度限制、格式验证(如邮箱、电话号码)等。 3. **HTTP请求**:通常使用POST请求来提交...

    struts2批量提交数据

    在Web应用中,这通常涉及到用户上传一个包含多条记录的数据文件,或者通过网页表单一次性输入多条数据。这种处理方式提高了数据处理效率,减少了网络通信次数。 ### 二、Struts2批量提交的实现步骤 1. **创建...

    Extjs4后台框架

    对于数据验证,ExtJS4的表单组件提供了丰富的验证规则,但后端同样需要进行数据验证,以确保数据的完整性和一致性。这可能涉及到后端框架的验证机制,例如在Java中的Hibernate Validator或Spring Validation。 最后...

    C#大文件上传源码哦

    虽然它不直接影响文件上传,但它确保了项目的版本控制和元数据一致性。 7. **Default.aspx**: 可能是网站的首页,提供用户访问其他页面(如Upload.aspx)的入口,或者展示关于文件上传的简单说明。 8. **.cs文件...

    网站后台管理模板

    9. **文件管理**:虽然没有直接提及,但后台管理模板往往包含文件上传、下载和预览功能,对于处理附件或多媒体内容的网站尤为重要。 通过使用这样的网站后台管理模板,开发者可以专注于业务逻辑的实现,而无需从零...

    Bootstrap通用后台管理模板

    模板中包含了数据添加功能,这意味着它支持用户通过前端界面进行数据输入,这对于后台数据的管理和维护至关重要。这种功能通常涉及表单验证、AJAX异步提交以及与后端服务器的交互,如JSON格式的数据交换,实现无刷新...

    上传HTML模板

    在现代Web应用中,文件上传功能是必不可少的,无论是让用户上传头像、分享文档还是提交作业。这种模板通常会包含JavaScript、CSS和HTML代码,以实现用户友好的界面和流畅的上传流程。 HTML5是这个模板的核心,它是...

    html后台模板

    在后台模板中,CSS用于设定颜色、字体、间距、布局等视觉效果,使得后台界面呈现出一致性和专业感。开发者可以根据品牌风格或个人喜好调整CSS样式。 3. **jQuery**:jQuery是一个广泛使用的JavaScript库,简化了...

    PHP表单生成器,快速生成现代化的form表单

    这些组件的集成使得创建功能齐全的表单变得简单,无论是在后台管理界面还是在用户交互的前端页面,都能提供直观且一致的用户体验。 在实际应用中,PHP表单生成器可以广泛应用于各种场景,例如在线调查、注册表单、...

    html5网站后台源码

    2. **form.html**: 此文件通常涉及表单设计,这在后台管理中至关重要,因为管理员经常需要填写和提交数据,如用户管理、内容发布或设置更改。 3. **ui.html**: UI(用户界面)文件关注的是交互元素和组件的设计,如...

    asp.net个人文件柜

    存储文件在数据库的优势包括数据一致性、安全性和易于备份,但可能会增加数据库的大小和查询复杂性。 3. **文件管理**:在个人文件柜中,用户可能需要查看、下载、删除已上传的文件。这需要在后台实现对应的接口,...

    后台管理系统模版

    5. **Forms.html** - 在后台管理系统中,表单用于收集和提交用户数据,如添加新用户、编辑信息、提交反馈等。这个文件可能包含不同类型的输入字段、按钮、验证规则等,帮助开发者快速创建用户交互界面。 6. **...

    Java表格数据导出Excel&Excel数据导入到数据库

    在导入数据时,应确保数据的完整性和一致性,防止SQL注入等安全问题。 综上所述,这个项目展示了如何利用Java和相关库实现在Web应用中与Excel文件的交互,以及如何结合前端异步文件上传功能,提升用户体验。对于...

    电网分分步骤注册表单代码.rar_mousegco_togetherxzo_电网分分步骤注册表单代码

    7. **文件上传**:虽然“jiaoben3955”看起来不像标准的文件名,但可能是某个特定功能的代码文件,例如,如果注册表单允许用户上传头像或其他文件,那么这部分代码会处理文件的上传、存储和大小验证。 8. **接口...

    实用Spring+Struts+Hibernate做的文件上传模块

    在文件上传模块中,Spring可以用来管理Bean,如上传服务、文件存储服务等,以及负责事务管理,确保文件操作的原子性和一致性。通过配置XML或使用Java配置,我们可以定义Bean的生命周期和依赖关系,使得代码更易于...

Global site tag (gtag.js) - Google Analytics