在公司开发一个后台管理系统时有这样的需求:提交一个表单时,要把表单域内容和上传的文件内容(可以是多个上传文件)一并提交到后台去,并且数据库持久化失败后数据要回滚且文件不应该上传上去,如果文件上传失败同样数据库也要回滚。
我的做法是:
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属性明确指出抛出哪种异常需要回滚
相关推荐
如果表单中包含文件上传,我们可以使用@MultipartConfig注解来处理文件上传。这种方法可以简化文件上传的处理过程,并且提高上传的安全性。 实体类的设计 在处理表单数据时,我们需要设计一个实体类来存储表单数据...
- **文件上传**:用户上传文件后,无需整个页面重新加载即可看到上传状态或结果。 - **评论提交**:用户提交评论后,评论立即显示在页面上而无需刷新整个页面。 - **表单验证**:实时验证表单输入,及时反馈错误信息...
【绿色表单提交商务网页模板】是一个专门设计用于商务场景的网页模板,其核心功能是提供一个用户友好的...开发者可以将这些文件上传到服务器,然后根据需要进行配置和调整,以创建一个符合自身需求的商务表单提交网页。
可以通过修改模板的SCSS或CSS文件,调整表单元素的颜色、边框、间距等属性,同时注意保持与模板其他部分的视觉一致性。 7. **表单布局优化**:根据表单内容的复杂性,可能需要调整布局,如使用栅格系统进行分栏布局...
在ASP.NET 3.5框架下,多文件上传是一个常见的需求,特别是在开发涉及用户交互、数据提交和资源管理的Web应用程序时。以下是对"C#多文件上传实例代码"这一主题的详细解释: **多文件上传的基本概念:** 多文件上传...
2. **数据验证**:前端验证可以提供即时反馈,但后端验证是必需的,以确保数据的安全性和一致性。这包括对必填字段的检查、长度限制、格式验证(如邮箱、电话号码)等。 3. **HTTP请求**:通常使用POST请求来提交...
在Web应用中,这通常涉及到用户上传一个包含多条记录的数据文件,或者通过网页表单一次性输入多条数据。这种处理方式提高了数据处理效率,减少了网络通信次数。 ### 二、Struts2批量提交的实现步骤 1. **创建...
对于数据验证,ExtJS4的表单组件提供了丰富的验证规则,但后端同样需要进行数据验证,以确保数据的完整性和一致性。这可能涉及到后端框架的验证机制,例如在Java中的Hibernate Validator或Spring Validation。 最后...
虽然它不直接影响文件上传,但它确保了项目的版本控制和元数据一致性。 7. **Default.aspx**: 可能是网站的首页,提供用户访问其他页面(如Upload.aspx)的入口,或者展示关于文件上传的简单说明。 8. **.cs文件...
9. **文件管理**:虽然没有直接提及,但后台管理模板往往包含文件上传、下载和预览功能,对于处理附件或多媒体内容的网站尤为重要。 通过使用这样的网站后台管理模板,开发者可以专注于业务逻辑的实现,而无需从零...
模板中包含了数据添加功能,这意味着它支持用户通过前端界面进行数据输入,这对于后台数据的管理和维护至关重要。这种功能通常涉及表单验证、AJAX异步提交以及与后端服务器的交互,如JSON格式的数据交换,实现无刷新...
这些组件的集成使得创建功能齐全的表单变得简单,无论是在后台管理界面还是在用户交互的前端页面,都能提供直观且一致的用户体验。 在实际应用中,PHP表单生成器可以广泛应用于各种场景,例如在线调查、注册表单、...
在现代Web应用中,文件上传功能是必不可少的,无论是让用户上传头像、分享文档还是提交作业。这种模板通常会包含JavaScript、CSS和HTML代码,以实现用户友好的界面和流畅的上传流程。 HTML5是这个模板的核心,它是...
在后台模板中,CSS用于设定颜色、字体、间距、布局等视觉效果,使得后台界面呈现出一致性和专业感。开发者可以根据品牌风格或个人喜好调整CSS样式。 3. **jQuery**:jQuery是一个广泛使用的JavaScript库,简化了...
2. **form.html**: 此文件通常涉及表单设计,这在后台管理中至关重要,因为管理员经常需要填写和提交数据,如用户管理、内容发布或设置更改。 3. **ui.html**: UI(用户界面)文件关注的是交互元素和组件的设计,如...
存储文件在数据库的优势包括数据一致性、安全性和易于备份,但可能会增加数据库的大小和查询复杂性。 3. **文件管理**:在个人文件柜中,用户可能需要查看、下载、删除已上传的文件。这需要在后台实现对应的接口,...
5. **Forms.html** - 在后台管理系统中,表单用于收集和提交用户数据,如添加新用户、编辑信息、提交反馈等。这个文件可能包含不同类型的输入字段、按钮、验证规则等,帮助开发者快速创建用户交互界面。 6. **...
在导入数据时,应确保数据的完整性和一致性,防止SQL注入等安全问题。 综上所述,这个项目展示了如何利用Java和相关库实现在Web应用中与Excel文件的交互,以及如何结合前端异步文件上传功能,提升用户体验。对于...
7. **文件上传**:虽然“jiaoben3955”看起来不像标准的文件名,但可能是某个特定功能的代码文件,例如,如果注册表单允许用户上传头像或其他文件,那么这部分代码会处理文件的上传、存储和大小验证。 8. **接口...
在文件上传模块中,Spring可以用来管理Bean,如上传服务、文件存储服务等,以及负责事务管理,确保文件操作的原子性和一致性。通过配置XML或使用Java配置,我们可以定义Bean的生命周期和依赖关系,使得代码更易于...