JavaWeb——JSP开发2
使用JSP+Servlet实现文件的上传和下载功能
1、文件模型
首先是文件本身,这里创建一个类记录文件的名字和内容:
public class Attachment {
private String name;
private byte[] contents; public Attachment() {
} public String getName() {
return this.name;
} public void setName(String name) {
this.name = name;
} public byte[] getContents() {
return this.contents;
} public void setContents(byte[] contents) {
this.contents = contents;
}
}
其次在创建一个类记录上传者的信息,信息有用户名、主题、文件描述、已经上传的文件
public class Ticket {
private String customerName;
private String subject;
private String body;
private Map<String, Attachment> attachments = new LinkedHashMap(); public Ticket() {
} public String getCustomerName() {
return this.customerName;
} public void setCustomerName(String customerName) {
this.customerName = customerName;
} public String getSubject() {
return this.subject;
} public void setSubject(String subject) {
this.subject = subject;
} public String getBody() {
return this.body;
} public void setBody(String body) {
this.body = body;
} public Attachment getAttachment(String name) {
return (Attachment)this.attachments.get(name);
} public Collection<Attachment> getAttachments() {
return this.attachments.values();
} public void addAttachment(Attachment attachment) {
this.attachments.put(attachment.getName(), attachment);
} public int getNumberOfAttachments() {
return this.attachments.size();
}
}
2、页面逻辑
这个demo将会实现三个页面
- 默认首页,提供跳转去上传页面的链接,以及已经上传的文件列表,文件列表中文件的主题名将链接到文件的详细信息页面
- 上传文件页面,这里客户可以填写文件的详细信息,并选择文件上传,点击Submit提交之后将会进入文件的详细信息页面,表示文件成功上传
- 文件详细信息页面会展示文件的详细信息,并提供文件下载链接,和返回第一个页面的链接
3、代码逻辑
- 使用一个LinkedHashMap保存已经上传的文件信息,使用一个volatile类型的变量记录文件的id。
- 使用action进行页面的重定向,以及上传、下载功能。
public class TicketServlet extends HttpServlet
{
private volatile int TICKET_ID_SEQUENCE = 1; private Map<Integer, Ticket> ticketDatabase = new LinkedHashMap<>(); @Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String action = request.getParameter("action");
if(action == null) {
action = "list";
}
System.out.println(action);
switch(action)
{
case "create":
//进入上传文件页面
this.showTicketForm(request, response);
break;
case "view":
//进入文件详细信息页面
this.viewTicket(request, response);
break;
case "download":
//实现下载功能
this.downloadAttachment(request, response);
break;
case "list":
default:
//进入默认页面
this.listTickets(request, response);
break;
}
} @Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String action = request.getParameter("action");
if(action == null) {
action = "list";
}
switch(action)
{
case "create":
//实现上传功能
this.createTicket(request, response);
break;
case "list":
default:
//进入默认页面
response.sendRedirect("tickets");
break;
}
}
4、三个页面的JSP
- 默认界面,将接收来自请求的ticketDatabase这个map,然后通过判断这个map的大小展示已上传文件列表,还有就是还提供了两个链接修改action的值实现重定向
<%@ page session="false" import="java.util.Map" %>
<%
@SuppressWarnings("unchecked")
Map<Integer, Ticket> ticketDatabase =
(Map<Integer, Ticket>)request.getAttribute("ticketDatabase");
%>
<!DOCTYPE html>
<html>
<head>
<title>Customer Support</title>
</head>
<body>
<h2>Tickets</h2>
<a href="<c:url value="/tickets">
<c:param name="action" value="create" />
</c:url>">Create Ticket</a><br /><br />
<%
if(ticketDatabase.size() == 0)
{
%><i>There are no tickets in the system.</i><%
}
else
{
for(int id : ticketDatabase.keySet())
{
String idString = Integer.toString(id);
Ticket ticket = ticketDatabase.get(id);
%>Ticket #<%= idString %>: <a href="<c:url value="/tickets">
<c:param name="action" value="view" />
<c:param name="ticketId" value="<%= idString %>" />
</c:url>"><%= ticket.getSubject() %></a> (customer:
<%= ticket.getCustomerName() %>)<br /><%
}
}
%>
</body>
</html>
- 文件上传页面,提供用户填写信息的输入框,提供点击Submit按钮进行跳转和上传文件,将action的值赋值为create
<%@ page session="false" %>
<!DOCTYPE html>
<html>
<head>
<title>Customer Support</title>
</head>
<body>
<h2>Create a Ticket</h2>
<form method="POST" action="tickets" enctype="multipart/form-data">
<input type="hidden" name="action" value="create"/>
Your Name<br/>
<input type="text" name="customerName"><br/><br/>
Subject<br/>
<input type="text" name="subject"><br/><br/>
Body<br/>
<textarea name="body" rows="5" cols="30"></textarea><br/><br/>
<b>Attachments</b><br/>
<input type="file" name="file1"/><br/><br/>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
- 文件详细信息页面,打印文件的详细信息,提供下载链接(这个链接将action值修改为download),返回默认页面的链接
<%@ page session="false" %>
<%
String ticketId = (String)request.getAttribute("ticketId");
Ticket ticket = (Ticket)request.getAttribute("ticket");
%>
<!DOCTYPE html>
<html>
<head>
<title>Customer Support</title>
</head>
<body>
<h2>Ticket #<%= ticketId %>: <%= ticket.getSubject() %></h2>
<i>Customer Name - <%= ticket.getCustomerName() %></i><br /><br />
<%= ticket.getBody() %><br /><br />
<%
if(ticket.getNumberOfAttachments() > 0)
{
%>Attachments: <%
int i = 0;
for(Attachment a : ticket.getAttachments())
{
if(i++ > 0)
out.print(", ");
%><a href="<c:url value="/tickets">
<c:param name="action" value="download" />
<c:param name="ticketId" value="<%= ticketId %>" />
<c:param name="attachment" value="<%= a.getName() %>" />
</c:url>"><%= a.getName() %></a><%
}
%><br /><br /><%
}
%>
<a href="<c:url value="/tickets" />">Return to list tickets</a>
</body>
</html>
5、具体方法的实现
- listTickets方法将会把这个map传递给一会将要运行的JSP,然后通过方法getRequestDispatcher可以获得一个javax.servlet.RequestDispatcher,这个对象将用于处理针对指定路径的内部转发和包含,通过该对象,将请求转发给调用forward方法的listTickets.jsp
private void listTickets(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
request.setAttribute("ticketDatabase", this.ticketDatabase); request.getRequestDispatcher("/WEB-INF/jsp/view/listTickets.jsp")
.forward(request, response);
}
- showTicketForm方法将同样调用getRequestDispatcher,将请求转发给ticketForm.jsp
private void showTicketForm(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
request.getRequestDispatcher("/WEB-INF/jsp/view/ticketForm.jsp")
.forward(request, response);
}
- createTicket方法将在上传页面点击Submit之后调用,通过request.getParameter获取请求的参数,创建一个Ticket对象并设置其CustomerName、Subject、Body,之后使用request.getParts()获取上传的文件,获取一个Part对象filePart,调用processAttachment()方法将这个Part对象转化为Attachment对象,然后添加到Ticket对象中,再然后将TICKET_ID_SEQUENCE加一作为id放入Map中,然后重定向到文件的详细信息页面
private void createTicket(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
Ticket ticket = new Ticket();
ticket.setCustomerName(request.getParameter("customerName"));
ticket.setSubject(request.getParameter("subject"));
ticket.setBody(request.getParameter("body")); Part filePart = request.getPart("file1");
if(filePart != null && filePart.getSize() > 0)
{
Attachment attachment = this.processAttachment(filePart);
if(attachment != null) {
ticket.addAttachment(attachment);
}
} int id;
synchronized(this)
{
id = this.TICKET_ID_SEQUENCE++;
this.ticketDatabase.put(id, ticket);
} response.sendRedirect("tickets?action=view&ticketId=" + id);
}
这里的processAttachment方法实现了将这个Part对象转化为Attachment对象,具体是先从Part获得InputStream,并将其复制到Attachment对象中。然后还使用了getSubmittedFileName()获取文件名。
private Attachment processAttachment(Part filePart)
throws IOException
{
InputStream inputStream = filePart.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); int read;
final byte[] bytes = new byte[1024]; while((read = inputStream.read(bytes)) != -1)
{
outputStream.write(bytes, 0, read);
} Attachment attachment = new Attachment();
attachment.setName(filePart.getSubmittedFileName());
attachment.setContents(outputStream.toByteArray()); return attachment;
}
- viewTicket方法首先是获取id,然后根据这个id调用getTicket方法获取到Ticket对象。获取到Ticket对象之后把这个对象和id一起以及请求转发给viewTicket.jsp
private void viewTicket(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
String idString = request.getParameter("ticketId");
Ticket ticket = this.getTicket(idString, response);
if(ticket == null) {
return;
} request.setAttribute("ticketId", idString);
request.setAttribute("ticket", ticket); request.getRequestDispatcher("/WEB-INF/jsp/view/viewTicket.jsp")
.forward(request, response);
}
其次这个根据id获取Ticket的getTicket方法如果有什么错误将会被重定向到/tickets页面
private Ticket getTicket(String idString, HttpServletResponse response)
throws ServletException, IOException
{
if(idString == null || idString.length() == 0)
{
response.sendRedirect("tickets");
return null;
} try
{
Ticket ticket = this.ticketDatabase.get(Integer.parseInt(idString));
if(ticket == null)
{
response.sendRedirect("tickets");
return null;
}
return ticket;
}
catch(Exception e)
{
response.sendRedirect("tickets");
return null;
}
}
- downloadAttachment方法这个方法首先是根据id获取Ticket对象,然后从请求中获取文件的名字,根据这个name从Ticket中获取文件的Attachment对象。
private void downloadAttachment(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
String idString = request.getParameter("ticketId");
Ticket ticket = this.getTicket(idString, response);
if(ticket == null) {
return;
} String name = request.getParameter("attachment");
if(name == null)
{
response.sendRedirect("tickets?action=view&ticketId=" + idString);
return;
} Attachment attachment = ticket.getAttachment(name);
if(attachment == null)
{
response.sendRedirect("tickets?action=view&ticketId=" + idString);
return;
} response.setHeader("Content-Disposition",
"attachment; filename=" + attachment.getName());
response.setContentType("application/octet-stream"); ServletOutputStream stream = response.getOutputStream();
stream.write(attachment.getContents());
}
最后的这几行代码,用于处理浏览器的下载请求,响应中设置头Content-Disposition,将强制浏览器询问客户是保存还是下载文件,而不是在浏览器从查看文件,设置的文件类型是通用的/二进制内容类型的,这样容器就不会使用字符编码对该数据进行处理。最后使用ServletOutputStream将文件内容输出到响应中。如果希望实现大文件下载,应该将数据从文件的InputStream中复制到ResponseOutputStream ,并且经常刷新ResponseOutputStream,这样数据才能不断被发送到用户浏览器中。
JavaWeb——JSP开发2的更多相关文章
- JavaWeb——JSP开发1
1.什么是jsp,为什么要使用jsp. 再使用idea创建完一个web工程后,在webapp目录下会生成一个index.jsp 直接编译运行,网站将自动打开这样一个网页: 所以我们可以推测这个inde ...
- javaweb的开发模式
SUN公司推出JSP技术后,同时也推荐了两种web应用程序的开发模式,一种是JSP+JavaBean模式,一种是Servlet+JSP+JavaBean模式. 一.JSP+JavaBean开发模式 1 ...
- Java之JavaWeb项目开发开始准备
操作系统:Mac OS 10.11.6 Tomcat版本:9.0.0.M17 前言:部署Tomcat可以参考我一年前做的笔记:<在MAC下搭建JSP开发环境>,也可以参考大神写的挺好的&l ...
- 2017.11.6 JavaWeb-----第七章 JavaWeb常用开发模式与案例
JavaWeb-----第七章 JavaWeb常用开发模式与案例 (1)单纯的JSP页面开发模式 通过在JSP中的脚本标记,直接在JSP页面中实现各种功能.称为"单纯的JSP页面编程模式&q ...
- JavaWeb:JSP技术基础
JavaWeb:JSP技术 快速开始 介绍 JSP全称Java Server Pages,是一种动态网页开发技术.它使用JSP标签在HTML网页中插入Java代码.标签通常以<%开头以%> ...
- IntelliJ IDEA安装及jsp开发环境搭建
一.前言 现在.net国内市场不怎么好,公司整个.net组技术转型,就个人来说还是更喜欢.net,毕竟不是什么公司都像微软一样财大气粗开发出VS这样的宇宙级IDE供开发者使用,双击sln即可打开项目, ...
- JSP开发环境配置问题解答
有过JSP开发经验的同学对于JSP开发环境的配置一定非常的很有感触,十分的繁琐,有时因为一个小的问题导致我们配置的配置前功尽弃,本篇我将重点带领大家一起探讨一下关于JSP环境配置的一些常见问题,及解决 ...
- windows上JSP开发环境全搭建
JSP开发环境全搭建 最近需要用到JSP做项目,所以要配置JSP的开发环境,总结一下配置步骤以备以后再配置需要. 配置JAVA开发环境,配置JDK 下载JDK,在这里下载开发所需的JDK,可以根据自己 ...
- 一.JSP开发的工具下载与环境搭建
JSP技术的强势: (1)一次编写,到处运行.在这一点上Java比PHP更出色,除了系统之外,代码不用做任何更改. (2)系统的多平台支持.基本上可以在所有平台上的任意环境中开发,在任意环境中进行系统 ...
随机推荐
- Java设计模式学习笔记(一) 设计模式概述
前言 大约在一年前学习过一段时间的设计模式,但是当时自己的学习方式比较低效,也没有深刻的去理解.运用所学的知识. 所以现在准备系统的再重新学习一遍,写一个关于设计模式的系列博客. 废话不多说,正文开始 ...
- 浅谈labviEW定时器
Labview提供了五种定时器:普通定时器3种: Tick Count (ms). Wait(ms).Wait Until Next ms Multipule(等待下一个毫秒的整数倍) API函数定 ...
- 【带着canvas去流浪(11)】Three.js入门学习笔记
目录 一. 资料推荐及建议 二. Three.js中的基本概念 三.重点笔记 四.补充示例 示例代码托管在:http://www.github.com/dashnowords/blogs 博客园地址: ...
- SQL Server 函数的定义及使用
一.定义函数 1. 标量值函数: 返回一个确定类型的标量值,例如:int,char,bit等 --创建标量值函数 create function func_1(@func_parameter_1 in ...
- 每周一个js重要概念之一 调用堆栈
js写了也有两年多了,大到复杂的后台系统,小到页面,还有日均300万的网页主站,HTML5的适配页面等等. 框架也杂七杂八接触了不少,从小的jquery.bootstrap.echarts等等,到大一 ...
- 聊聊C语言的预编译指令include
"include"相信大家不会陌生,在我们写代码时,开头总会来一句"include XXX".include是干嘛用的,很多教材都提到了,因此这里不会再详细解释 ...
- 20131228-sql命令
开始 --cmd net start mssqlservernetnet stop mssqlserver
- VS2010 winform开发笔记---combox的SelectedIndexChanged事件及级联问题
DisplayMember绑定需要显示的数据表字段, 而ValueMember绑定需要获取选择的项的值. 然后通过 combo.SelectedValue就可以取得选中项的值了. DisplayMem ...
- py+selenium遇见IE,元素只有name属性【神奇解决】
问题:当需要自动化测试某系统,而该系统只兼容IE8,怎么办? IE8的问题:IE8不支持getElementByName,而属性中又没有ID,定位难度较大. IE8以下不兼容getElementByN ...
- 简单函数编写_strcpy、_stroverchg、_strcmp
字符串复制函数 void _strcpy(char *tar, const char * res) { char *p = tar; while(assert(tar && res), ...