文件上传和下载[struts1]
一、文件上传的基本操作(读、写操作)
工程结构:
jar包:
index.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>主页</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
<jsp:forward page="/WEB-INF/register.jsp" />
</body>
</html>
register.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>注册页面</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
<h3>用户注册</h3>
<form action="<%=basePath%>register.do" method="post" enctype="multipart/form-data">
用户名: <input type="text" name="username"/><br/><br/>
上传头像: <input type="file" name="myPhoto"/>
<input type="submit" value="点击注册"/>
</form>
</body>
</html>
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>/WEB-INF/struts-config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
struts-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
"http://struts.apache.org/dtds/struts-config_1_3.dtd">
<struts-config>
<form-beans>
<form-bean name="userForm" type="com.itcast.struts1.form.UserForm" />
</form-beans>
<action-mappings>
<action path="/register" name="userForm"
type="com.itcast.struts1.action.RegisterAction">
<forward name="registerOk" path="/WEB-INF/registerOk.jsp" />
</action>
</action-mappings>
</struts-config>
UserForm.java:
package com.itcast.struts1.form;
import org.apache.struts.action.ActionForm;
import org.apache.struts.upload.FormFile;
@SuppressWarnings("serial")
public class UserForm extends ActionForm {
private String username;
private FormFile myPhoto;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public FormFile getMyPhoto() {
return myPhoto;
}
public void setMyPhoto(FormFile myPhoto) {
this.myPhoto = myPhoto;
}
}
RegisterAction.java:
package com.itcast.struts1.action;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.upload.FormFile;
import com.itcast.struts1.form.UserForm;
public class RegisterAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
UserForm userForm = (UserForm) form;
// 1. 拿到文件, 获取文件的各种信息
FormFile file = userForm.getMyPhoto();
String fileName = file.getFileName();
// 2. 设置文件上传后的存放目录 D:\tomcat7\apache-tomcat-7.0.75\webapps\struts1_fileUpAndLoad\file
String keepFilePath = this.getServlet().getServletContext().getRealPath("file");
InputStream is = null; // 输入流: 用于读取文件
OutputStream os = null; // 输出流: 用于写入文件
try {
// 3. 获取输入流和输出流
is = file.getInputStream();
os = new FileOutputStream(keepFilePath + "\\" + fileName);
// 4. 读取文件
int len = 0;
byte bytes[] = new byte[1024];
while ((len=is.read(bytes)) > 0) {
// 5. 边读边写
os.write(bytes, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 6. 关闭输出流和输入流
os.close();
is.close();
}
return null;
}
}
registerOk.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>注册成功</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
<a href="#">查看用户信息</a>
<hr/>
<h3>注册成功!</h3>
</body>
</html>
测试:
打开目录D:\tomcat7\apache-tomcat-7.0.75\webapps\struts1_fileUpAndLoad\file, 图片上传成功:
-----------------------------------------------------------------------------------
以上文件上传的问题:
没有考虑到文件重名的问题
解决方法:
1. 自定义一个方法, 使用“年+月+日+时+分+秒+毫秒”作为文件名;
2. 使用UUID类的RandomUUID()方法, 产生一个十六进制的随机数;
这里使用第2种方法, 创建一个工具类: com.itcast.struts1.util.MyUtil.java
package com.itcast.struts1.util;
import java.util.UUID;
public class MyUtil {
// 获取新的文件名称
public static String getNewFileName(String fileName) {
// heart.jpg, 获取.所在的索引
int beginIndex = fileName.lastIndexOf(".");
// 产生一个十六进制的随机数
UUID uuid = UUID.randomUUID();
// 拼接成一个新的文件名称
String newFileName = uuid + fileName.substring(beginIndex, fileName.length());
// 返回新的文件名称
return newFileName;
}
}
修改: RegisterAction.java
测试:
上传了同一张图片, 不会覆盖原文件:
----------------------------------------------------------------------
问题2: 文件名称有中文字符, 会出现乱码
测试:
上传一张 中文名称.jpg 图片
后台打印:
fileName: 涓枃鍚嶇О.jpg
newFileName: 0fce4ea7-a27c-40e2-8b9b-47f84ca7c360.jpg
出现中文乱码, 解决方法: 用过滤器解决
(1) 创建过滤器类
创建包: com.itcast.struts1.filter
包下创建类: MyFilter.java
package com.itcast.struts1.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
// 设置request请求的编码格式
arg0.setCharacterEncoding("UTF-8");
// 让过滤器链继续执行
arg2.doFilter(arg0, arg1);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
@Override
public void destroy() {
}
}
(2) 在web.xml中配置过滤器
<!-- 配置过滤器 -->
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.itcast.struts1.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
再次测试:
后台打印:
fileName: 中文名称.jpg
newFileName: 86d02931-60b7-4872-a082-0ba3b9eeb720.jpg
解决了中文乱码问题
---------------------------------------------------------------------
二、文件下载的基本操作
注意: 在下载文件的时候, 要给用户显示原来的文件名, 所以要将用户的信息保存到数据库中(数据库中只存放了用户图片的全路径)
mysql.sql: 创建数据库和数据表
注意要创建两个字段, 分别用于保存旧的文件名称(用户的文件名称)和新的文件名称(随机生成的文件名称)
CREATE DATABASE test;
USE test;
CREATE TABLE user(
username VARCHAR(64) UNIQUE NOT NULL,
oldFileName VARCHAR(128) NOT NULL,
newFileName VARCHAR(128) NOT NULL
);
创建domain类: com.itcast.struts1.domain.User.java
package com.itcast.struts1.domain;
public class User {
private String username;
private String oldFileName;
private String newFileName;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getOldFileName() {
return oldFileName;
}
public void setOldFileName(String oldFileName) {
this.oldFileName = oldFileName;
}
public String getNewFileName() {
return newFileName;
}
public void setNewFileName(String newFileName) {
this.newFileName = newFileName;
}
}
在com.itcast.struts1.util包下创建连接数据库的DBHelper.java:
package com.itcast.struts1.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class DBHelper {
// 数据库连接参数
public static final String DRIVERCLASS = "com.mysql.jdbc.Driver";
public static final String URL = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";
public static final String USRENAME = "root";
public static final String PASSWORD = "123456";
// Connection
public static Connection getConn() {
Connection conn = null;
try {
Class.forName(DRIVERCLASS);
conn = DriverManager.getConnection(URL, USRENAME, PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
// PrepareStatement
public static PreparedStatement prepare(Connection conn, String sql) {
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(sql);
} catch (SQLException e) {
e.printStackTrace();
}
return ps;
}
// 关闭数据库, 释放资源
public static void close(ResultSet rs) {
if (rs != null) {
try {
rs.close();
rs = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void close(PreparedStatement ps) {
if (ps != null) {
try {
ps.close();
ps = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close(Connection conn) {
if (conn != null) {
try {
conn.close();
conn = null;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
创建Service: com.itcast.struts1.service.UserService.java
package com.itcast.struts1.service;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.itcast.struts1.domain.User;
import com.itcast.struts1.util.DBHelper;
public class UserService {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
// 添加用户
public boolean addUser(User user) {
boolean flag = true;
String sql = "INSERT INTO user VALUES(?,?,?)";
conn = DBHelper.getConn();
try {
ps = DBHelper.prepare(conn, sql);
ps.setString(1, user.getUsername());
ps.setString(2, user.getOldFileName());
ps.setString(3, user.getNewFileName());
ps.executeUpdate();
} catch (SQLException e) {
flag = false;
e.printStackTrace();
} finally {
DBHelper.close(ps);
DBHelper.close(conn);
}
return flag;
}
}
修改: RegisterAction.java
String resultPage = null; // 结果跳转
return mapping.findForward(resultPage);
修改struts-config.xml:
<!-- 全局跳转 -->
<global-forwards>
<forward name="error" path="/WEB-INF/error.jsp" />
</global-forwards>
测试:
英文文件名测试:
后台打印:
数据库:
tomcat的图片存放目录:
中文文件名测试:
后台打印:
数据库:
tomcat的图片存放目录:
查数据库:
问题: 数据库中出现了中文乱码!!!
重新设定编码:
set character_set_connection = utf8;
set character_set_server = utf8;
重新查数据库, 还是乱码:
检查DBHelper.java:
public static final String URL = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";
去掉amp;之后再测试:
-------------------------------------------------------
文件下载:
registerOk.jsp:
<h3>恭喜您! 注册成功!</h3>
<hr/>
<a href="<%=basePath%>getUserList.do">查看用户信息</a>
struts-config.xml:
<!-- 用户列表 -->
<action path="/getUserList" type="com.itcast.struts1.action.UserListAction">
<forward name="userList" path="/WEB-INF/userList.jsp" />
</action>
UserService.java:
// 获取用户列表
public List<User> getUserList() {
String sql = "SELECT * FROM user";
Connection conn = DBHelper.getConn();
List<User> userList = new ArrayList<>();
try {
PreparedStatement ps = DBHelper.prepare(conn, sql);
rs = ps.executeQuery();
// 对查询结果进行二次封装
while (rs.next()) {
User user = new User();
// 获取结果集并封装到User对象中
user.setUsername(rs.getString(1));
user.setOldFileName(rs.getString(2));
user.setNewFileName(rs.getString(3));
// 将User对象添加集合
userList.add(user);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DBHelper.close(rs);
DBHelper.close(ps);
DBHelper.close(conn);
}
// 返回用户列表userList
return userList;
}
UserListAction.java:
package com.itcast.struts1.action;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import com.itcast.struts1.domain.User;
import com.itcast.struts1.service.UserService;
public class UserListAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
UserService userService = new UserService();
List<User> userList = userService.getUserList();
UserService userService = new UserService();
List<User> userList = userService.getUserList();
request.setAttribute("userList", userList);
return mapping.findForward("userList");
}
}
userList.jsp:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<h3>用户列表</h3>
<hr/>
<c:choose>
<c:when test="${!empty userList }">
<table border="1px" cellpadding="3" cellspacing="3">
<tr><td>用户名</td><td>用户头像</td><td>操作</td></tr>
<c:forEach items="${userList }" var="user">
<tr>
<td>${user.username }</td>
<td><img alt="${user.oldFileName }" src="<%=basePath%>/file/${user.newFileName}" width="100"></td>
<td><a href="#">点击下载</a></td>
</tr>
</c:forEach>
</table>
</c:when>
<c:otherwise>
<h4 style="color: red;">温馨提示: 无任何用户 !</h4>
</c:otherwise>
</c:choose>
测试:
------------------------------------------------------------------
文件下载:
registerOk.jsp
<h3>恭喜您! 注册成功!</h3>
<hr/>
<a href="<%=basePath%>getUserList.do">查看用户信息</a>
struts-config.xml
<!-- 点击下载 -->
<action path="/downLoadFile" type="com.itcast.struts1.action.DownLoadAction">
<forward name="goBackToUserList" path="/WEB-INF/userList.jsp" />
</action>
UserService.java:
// 根据用户名获取用户信息
public User getUserByUsername(String username) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
String sql = "SELECT * FROM user WHERE username = ?";
User user = null;
try {
conn = DBHelper.getConn();
ps = DBHelper.prepare(conn, sql);
ps.setString(1, username);
rs = ps.executeQuery();
while (rs.next()) {
user = new User();
user.setUsername(rs.getString(1));
user.setOldFileName(rs.getString(2));
user.setNewFileName(rs.getString(3));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DBHelper.close(ps);
DBHelper.close(conn);
}
// 返回查询到的用户对象
return user;
}
DownLoadAction.java:
package com.itcast.struts1.action;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import com.itcast.struts1.domain.User;
import com.itcast.struts1.service.UserService;
public class DownLoadAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
// 获取jsp页面传递过来的username
String username = request.getParameter("username");
String usernamePro = new String(username.getBytes("ISO-8859-1"), "UTF-8");
// 调用UserService的方法获取用户对象
UserService userService = new UserService();
User user = userService.getUserByUsername(usernamePro);
try {
// 设置文件头, 告诉浏览器有文件要下载, 文件名要设置编码
response.setContentType("text/html;charset=UTF-8");
String oldFileNameFilter = URLEncoder.encode(user.getOldFileName(), "UTF-8");
response.setHeader("Content-Disposition", "attachment;fileName=" + oldFileNameFilter);
} catch (Exception e) {
e.printStackTrace();
}
// 利用用户对象获取图片的绝对路径
String fileName = user.getNewFileName();
String fileAllPath = this.getServlet().getServletContext().getRealPath("/file") + "\\" + fileName;
// 获取文件输入流和输出流
FileInputStream fis = null;
OutputStream fos = null;
// 进行读写操作
byte []buffer = new byte[1204];
int len = 0;
try {
fis = new FileInputStream(fileAllPath);
fos = response.getOutputStream();
while ((len = fis.read(buffer)) > 0) { // 将文件流读到buffer中
fos.write(buffer, 0, len); // 边读边写到输出流fos中
}
} catch (Exception e) {
e.printStackTrace();
} finally {
fos.close();
fis.close();
}
return mapping.findForward("goBackToUserList");
}
}
userList.jsp:
<body>
<h3>用户列表</h3>
<hr/>
<c:choose>
<c:when test="${!empty userList }">
<table border="1px" cellpadding="3" cellspacing="3">
<tr><th>用户名</th><th>用户头像</th><th>操作</th></tr>
<c:forEach items="${userList }" var="user">
<tr>
<td>${user.username }</td>
<td><img alt="${user.oldFileName }" src="<%=basePath%>/file/${user.newFileName}" width="100"></td>
<td><a href="<%=basePath%>downLoadFile.do?username=${user.username}">点击下载</a></td>
</tr>
</c:forEach>
</table>
</c:when>
<c:otherwise>
<h4 style="color: red;">温馨提示: 无任何用户 !</h4>
</c:otherwise>
</c:choose>
</body>
测试:
可以正常下载图片, 但是后台报错:
java.lang.IllegalStateException: getOutputStream() has already been called for this response
报错原因是: out.getWrite()和out.getOutputStream冲突
解决方法: http://www.cnblogs.com/josephcnblog/articles/6880879.html
-----------------------------------------------------
问题1: 限制上传文件的大小
修改RegisterAction.java:
问题2: 限制上传文件的类型
文件类型可查看tomcat目录的conf目录下的web.xml文件:
问题3: 防止用户名重复
使用ajax技术动态刷新
register.jsp:
-------------------------
js:
<script type="text/javascript" src="<%=basePath%>scripts/jquery-1.3.1.js"></script>
<script type="text/javascript">
$(function() {
// 目标结果: <font color='red'>该用户名可以使用</font>
// 所以考虑返回HTML格式直接插入, 不需要解析
$("#checkUserName").blur(function() {
// 获取用户输入的用户名
var userNameInput = $("#checkUserName").val();
// 请求URL及参数
var url = "<%=basePath%>checkUserName.do?method=checkUserName";
var args = {"userNameInput": userNameInput, "time": new Date()};
// 发送Ajax请求
$.post(url, args, function(data) {
var message = $("#message").html(data).text();
if (message == "该用户名已经被使用") {
$("#register").attr("disabled", true);
} else {
$("#register").attr("disabled", false);
}
});
// 取消默认行为[页面跳转]
return false;
});
});
</script>
struts-config.xml:
<!-- 校验用户名是否重复 -->
<action path="/checkUserName" parameter="method"
type="com.itcast.struts1.action.CheckUserNameAction">
</action>
UserService.java:
// 校验用户名是否存在
public boolean isUserNameRepeat(String userNameInput) {
boolean flag = false; // 默认是不重复的
String sql = "SELECT username FROM user";
conn = DBHelper.getConn();
ps = DBHelper.prepare(conn, sql);
try {
rs = ps.executeQuery();
// 开始遍历, 如果用户名存在, 则flag = true
while (rs.next()) {
String username = rs.getString(1);
if (username.equals(userNameInput.trim())) {
flag = true;
}
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBHelper.close(rs);
DBHelper.close(ps);
DBHelper.close(conn);
}
return flag;
}
CheckUserNameAction.java:
public class CheckUserNameAction extends DispatchAction {
public void checkUserName(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
// 获取输入的用户名
String userNameInput = request.getParameter("userNameInput");
// 调用service方法校验
String result = null;
UserService userService = new UserService();
// <font color='red'>该用户名可以使用</font>
if (userService.isUserNameRepeat(userNameInput)) {
result = "<font color='red'>该用户名已经被使用</font>";
} else {
result = "<font color='green'>该用户名可以使用</font>";
}
// 打印校验结果
response.setContentType("text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
response.getWriter().print(result);
}
}
数据库:
测试:
问题4: 给每一个用户创建一个目录, 用于存放自己上传的图片
因为上传的图片很多, 因此给每个用户创建一个目录

浙公网安备 33010602011771号