Java for Web学习笔记(六五):Controller替代Servlet(7)上传和下载(自定义View)
来源:互联网 发布:双十一淘宝销售额 编辑:程序博客网 时间:2024/05/16 08:37
文件上传
文件上传使用的multipart,在之前介绍过。这里我们不采用xml配置,采用代码配置。之前我们采用的resolver为org.springframework.web.multipart.commons.CommonsMultipartResolver,API解析org.springframework.web.multipart.commons包是MultipartResolver implementation for Apache Commons FileUpload。本学习采用Servlet 3.1内置的multipart的支持,采用org.springframework.web.multipart.support.StandardServletMultipartResolver,这是Standard implementation of the MultipartResolver interface, based on the Servlet 3.0 Part API,因此我们无需引入commons-fileupload。
代码配置
(1) BootStrap:允许被设置multipart参数
public class BootStrap implements WebApplicationInitializer{ @Override public void onStartup(ServletContext container) throws ServletException { container.getServletRegistration("default").addMapping("/resource/*"); AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext(); rootContext.register(RootContextConfiguration.class); container.addListener(new ContextLoaderListener(rootContext)); AnnotationConfigWebApplicationContext servletContext = new AnnotationConfigWebApplicationContext(); servletContext.register(ServletContextConfiguration.class); ServletRegistration.Dynamic dispatcher = container.addServlet("springDispatcher", new DispatcherServlet(servletContext)); dispatcher.setLoadOnStartup(1); // 【1】在DispatcherServlet中允许并设置multipart的参数。 dispatcher.setMultipartConfig(new MultipartConfigElement( null /*location*/, 20_971_520L/*maxFileSize*/, 62_914_560L/*maxRequestSize*/, 512_000/*fileSizeThreshold*/)); dispatcher.addMapping("/"); // 【注】这里虽然和上传下载没有关系,但是如果我们采用代码设置配置,BootStrap是在web启动时运行,我们最好把所有的初始化的处理放在这里,而不是将其中一部分放入ServletContextListener,尽可能不要将初始化代码分在两个不同的地方。但是我们也注意到,WebApplicationInitializer是不提供web app退出的处理,所以ServletContextListener仍可能要用上。 initFilter(container); } private void initFilter(ServletContext container){ ... ... } }
(2) ServletContextConfiguration:设置multipart resolver
@Configuration@ComponentScan(basePackages = "cn.wei.flowingflying.customer_support.site", useDefaultFilters = false, includeFilters = @ComponentScan.Filter(Controller.class))public class ServletContextConfiguration { @Bean public ViewResolver viewResolver(){ InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setViewClass(JstlView.class); resolver.setPrefix("/WEB-INF/jsp/view/"); resolver.setSuffix(".jsp"); return resolver; } @Bean public RequestToViewNameTranslator viewNameTranslator(){ return new DefaultRequestToViewNameTranslator(); } //【2】Spring兼容旧的Servlet API。在Servlet3.0之前,并没有内置multipart的支持,需使用第三方,为兼容,Spring需要设置MultipartResolver来明确采用内置的还是第三方的。 // 例子采用了自带的org.springframework.web.multipart.support.StandardServletMultipartResolver,不引入第三方。 @Bean public MultipartResolver multipartResolver() { return new StandardServletMultipartResolver(); }}
jsp文件:add.jsp片段
既然学习了spring的form tag,我们就例子中使用。但是没有form:file,我们仍需要使用<input>的方式。
<form:form method="post" enctype="multipart/form-data" modelAttribute="ticketForm"> <form:label path="subject">Subject</form:label><br /> <form:input path="subject"/><br /><br /> <form:label path="body">Body</form:label><br /> <form:textarea path="body" rows="5" cols="30" /><br /><br /> <b>Attachments</b><br /> <input type="file" name="attachments" multiple="multiple"/><br /><br /> <input type="submit" value="Submit"/></form:form>对应的java类Form
public class Form{ private String subject; private String body; private List<MultipartFile> attachments; ... getters & setters ...}
Controller的代码片段
@RequestMapping(value = "create", method = RequestMethod.GET)public String create(Map<String, Object> model){ model.put("ticketForm", new TicketController.Form()); return "ticket/add";}/* 1、ticket是业务对象,form是Form对象(输入对象),这两者有关联,但通常不一样。我们再三强调,我们应将业务逻辑和用户UI逻辑分离 * 2、从session中获取用户的登录账号 * 3、采用spring form tag可以将form对象和页面呈现进行双向转换,对于页面转为form对象,使用普通的input并无影响 */@RequestMapping(value = "create", method = RequestMethod.POST)public View create(HttpSession session,Form form) throws IOException{ Ticket ticket = new Ticket(); ticket.setId(getNextTicketId()); ticket.setCustomerName((String)session.getAttribute("username")); ticket.setSubject(form.getSubject()); ticket.setBody(form.getBody()); ticket.setDateCreated(Instant.now()); for(MultipartFile filePart : form.getAttachments()){ logger.debug("Processing attachment for new ticket."); Attachment attachment = new Attachment(); attachment.setName(filePart.getOriginalFilename()); attachment.setContents(filePart.getBytes()); attachment.setMimeContentType(filePart.getContentType()); if(attachment.getName()!= null && attachment.getName().length() > 0 && attachment.getContents() != null && attachment.getContents().length > 0){ ticket.addAttachment(attachment); } } this.ticketDatabase.put(ticket.getId(), ticket); return new RedirectView("/ticket/view/" + ticket.getId(),true,false);}
文件下载
文件下载使用自定义的view来进行处理。
自定义下载view:DownloadingView
public class DownloadingView implements View{ private final String filename; private final String contentType; private final byte[] contents; public DownloadingView(String filename, String contentType,byte[] contents){ this.filename = filename; this.contentType = contentType; this.contents = contents; } @Override public String getContentType() { return this.contentType; } // render很有意思,参数包括servlet的request和response,以及controller的处理结果的数据存放model,可以根据model构造返回的http响应。 @Override public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { response.setHeader("Content-Disposition", "attachment; filename=" + this.filename); response.setContentType("application/octet-stream"); ServletOutputStream stream = response.getOutputStream(); stream.write(this.contents); }}
Controller的代码片段
// 1、在url中采用正则表达式,.表示匹配除“\r\n”之外的任何单个字符;+表示匹配前面的子表达式一次或多次(大于等于1次)// 2、判断如果{ticketId}无效,则跳转;进而如果{attachment}无效则跳转;最后进入自定义的view进行处理。// 3、自定义的View在构造函数中已经填入所需的信息,不采用model进行数据传递,因此不使用ModelAndView,采用返回View的方式@RequestMapping( value = "/{ticketId}/attachment/{attachment:.+}", method = RequestMethod.GET )public View download(@PathVariable("ticketId") long ticketId, @PathVariable("attachment") String name){ Ticket ticket = ticketDatabase.get(ticketId); if(ticket == null) return getListRedirectView(); Attachment attachment = ticket.getAttachment(name); if(attachment == null){ logger.info("Requested attachment {} not found on ticket {}.", name, ticketId); return this.getListRedirectView(); } return new DownloadingView(attachment.getName(),attachment.getMimeContentType(), attachment.getContents());}
相关链接: 我的Professional Java for Web Applications相关文章
阅读全文
1 0
- Java for Web学习笔记(六五):Controller替代Servlet(7)上传和下载(自定义View)
- Java for Web学习笔记(六三):Controller替代Servlet(5)Model和View
- Java for Web学习笔记(六二):Controller替代Servlet(4)方法返回值
- Java for Web学习笔记(五九):Controller替代Servlet(1)请求匹配
- Java for Web学习笔记(六十):Controller替代Servlet(2)方法中的参数
- Java for Web学习笔记(六一):Controller替代Servlet(3)body映射到参数
- Java for Web学习笔记(六四):Controller替代Servlet(6)Spring Form Tag
- Java for Web学习笔记(九):Servlet(7)上传文件
- Java for Web学习笔记(三六):自定义tag(4)自定义Tag文件
- Java for Web学习笔记(六):Servlet(4)HttpServletResponse
- Java for Web学习笔记(五六):Spring框架简介(5)自动识别
- Java for Web学习笔记(五):Servlet(3)HttpServletRequest
- Java for Web学习笔记(六六):Service和Repository(1)抽象分层
- Java for Web学习笔记(六九):Service和Repository(4)Principal
- Java for Web学习笔记(八六):消息和集群(1)一般性了解
- Java for Web学习笔记(八三):RESTful(3)Controller
- Java Servlet学习笔记(六)Servlet Cookies处理
- Java for Web学习笔记(三三):自定义tag(1)篇外:Method和Function
- 苹果面试8大难题及答案
- 移动端与PHP服务端接口通信流程设计(基础版)
- Delphi 跨语言环境 乱码问题
- struct hostent *host = gethostbyname2([hostName UTF8String], AF_INET);
- 如何解决GET请求中文乱码问题?
- Java for Web学习笔记(六五):Controller替代Servlet(7)上传和下载(自定义View)
- 这是我想要学习的记录而已
- TeamViewer远程唤醒主机实战教程(多图)
- STL容器迭代器失效浅析
- Golang单元测试之httptest使用
- K均值聚类(K-means)
- Uva.202 Repeating Decimals
- springMVC设置不拦截静态资源
- 快速移动、淡入效果fadeIn()未完成就无法进行display的none操作