初次整理struts2文件上传,如有疑问或发现错误,恳请评论区讨论或QQ(545734785)告知我
目录
jar包
文件上传--html前端
struts.xml配置(包括文件上传大小限制)
java action
jar包
文件上传需要的两个jar包,可以在网盘下载。
§commons-fileupload-1.3.3.jar
§commons-io-2.6.jar
链接:https://pan.baidu.com/s/1BO3G6QOgj4bAOSUr40RFZQ
提取码:w223
复制这段内容后打开百度网盘手机App,操作更方便哦
文件上传--html前端
①form标签方式
特别注意:method和enctype属性必须跟下面相同,请牢记input的name,我这里叫upFile
<div>
<form action="<%=rootPath%>/file!file_upload.action" method="post" enctype="multipart/form-data">
<input type="file" name="upFile" required>
<button type="submit" class="btn btn-success">上传</button>
</form>
</div>
②ajax异步提交表单方式
html:
form onsubmit属性是提交前校验,里面我们直接通过ajax异步提交。show_photo函数是预览照片的,可有可无。accept="image/*"则只能上传图片
<form id="form_photo" onsubmit="return check_photo();" method="post">
<label for="preview">照片预览</label><br>
<img id="preview">
<input name="photo" type="file" accept="image/*" onchange="show_photo(this)">
<button class="btn btn-success">保存</button>
</form>
javascript:
check_photo函数实现ajax。文件上传需要用FormData对象传值,第3行是将input的文件添加到FormData对象中,注意"upFile"是传到后台的文件对象名,同①中的input name属性!
特别注意 return false; 即阻止form标签提交表单,否则会造成ajax和form双方都提交表单。
function check_photo() {
var formData = new FormData();
formData.append('upFile', $("input[name='photo']")[0].files[0]); //添加图片信息的参数
$.ajax({
url:"<%=rootPath%>/user!modify_photo", //后台地址,即action
type:"post", //提交方式post
data:formData,
dataType:"json", //回传数据类型json,即success的参数result是json类型
cache: false, //上传文件不需要缓存
processData: false, // 告诉jQuery不要去处理发送的数据
contentType: false, // 告诉jQuery不要去设置Content-Type请求头
success:function (result) {
result=$.parseJSON(result) //字符串转换为json
alert(result)
},
error:function (res) {
alert("文件保存失败!请保证图片大小不超过8MB")
}
})
return false; //一定要return false,否则form会自己提交一次
}
*js展示图片,可有可无
function show_photo(fileDom) {
$("#photo_alert_s").hide()
//判断是否支持FileReader
if(window.FileReader) {
var reader = new FileReader();
} else {
alert("您的设备不支持图片预览功能,如需该功能请更换或升级您的设备!");
}
//获取文件
var file = fileDom.files[0];
var imageType = /^image\//;
//是否是图片
if(!imageType.test(file.type)) {
alert("请选择图片!");
return;
}
//读取完成
reader.onload = function(e) {
//获取图片dom
var img = document.getElementById("preview");
//图片路径设置为读取的图片
img.src = e.target.result;
};
reader.readAsDataURL(file);
}
注意:上面①②二选一即可。
struts.xml配置(包括文件上传大小限制)
- action配置
前端使用①方式提交表单,则关注下面代码的package的action。
如果使用方式②,则关注action中,一、必须有一个type="json"的result,二、result内含一句<param name="root">res</param>,【三 四 可以先忽略:三、action类中执行方法后,必须返回该result标签的name。四、action类中必须有一个字符串成员变量res,get set方法必需。】
- struts2文件限制
struts2文件上传大小默认限制2M,超过2M会被拦截而上传失败。修改struts.xml
struts标签中添加 <constant name="struts.multipart.maxSize" value="2000100100" /> <!-- 项目全局文件限制大小修改为2G -->
在action中添加interceptor-ref标签,单独限制该action的限制(示例如下),可以不添加,则遵循全局。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<constant name="struts.multipart.maxSize" value="2000100100" /> <!-- 项目全局限制2G -->
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<constant name="struts.devMode" value="false"/>
<package name="file_oper" namespace="/" extends="struts-default,json-default" strict-method-invocation="false">
<action name="file_*" class="action.FileAction" method="{1}">
<result name="success">/files.jsp</result>
<result name="login">/userpage/login.jsp</result>
<result name="error">/error.jsp</result>
</action>
<action name="file" class="action.FileAction">
<result name="json" type="json">
<!-- 返回到前台json数据 action里有一个String result-->
<param name="root">res</param>
</result>
<result name="login">/userpage/login.jsp</result>
<result name="success" type="redirect">file_getFiles.action</result>
<result name="error">/error.jsp</result>
<interceptor-ref name="fileUpload"> <!-- 当前action文件上传大小限制80M -->
<param name="maximumSize">80000000</param>
</interceptor-ref>
<interceptor-ref name="defaultStack" /> <!-- 默认拦截器 -->
</action>
</package>
</struts>
- tomcat文件上传限制
修改stuts.xml后,请先尝试能否成功上传大文件。实践发现,tomcat不改并不影响,若仍然上传失败,再考虑tomcat:
tomcat默认post文件上传限制大小为2M,也就是超过2M的文件都被tomcat拦截。解决方法是在tomcat/conf/server.xml中加一句话。找到<Connector port="8080" .... />标签,在其中加一句 maxPostSize="-1" ,如果-1不行,请尝试0,这样tomcat就会忽略文件大小检查。你也可以改成maxPostSize="100",这样表示tomcat将限制文件大小100B(字节)
另外connectionTimeout默认20000(2秒)可能会导致文件还没上传完成,就因超时被tomcat终止了,可以适当增大该值。
修改后(添加了第三行):
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
maxPostSize="-1"
redirectPort="8443" />
java action
注意:如果使用ajax方式提交表单,则下面的函数返回值改为 return “json”; 回顾一下上面struts.xml中的result type="json"
下面第8~10行必须有,这是接收文件用的,且有set方法。
函数开头对用户进行了一些校验,你可以根据自己的需要调整。
public class FileAction extends ActionSupport implements ModelDriven<SqlFile>, ServletRequestAware, SessionAware {
public SqlFile sqlFile = new SqlFile();
private HttpServletRequest request;
private Map<String,Object> session;
private String result; //用于返回json数据
// upFile与前台传来的文件名一致!需要有set方法!
private java.io.File upFile; //得到上传的文件
private String upFileContentType; //得到文件的类型
private String upFileFileName; //得到文件的名称
public String getFiles(){
User user = (User) session.get("user");
if(user==null)return LOGIN;
List<SqlFile> list=new FileDaoImpl().findAll("-created");
request.setAttribute("files",list);
return SUCCESS;
}
public String file_upload(){
User user = (User) session.get("user");
if(user==null)return LOGIN;
if(user.getIs_super()==0){
request.setAttribute("res",false);
request.setAttribute("msg","请求被禁止! 用户权限不足!");
return ERROR;
}
if(upFile==null){
request.setAttribute("res",false);
request.setAttribute("msg","请求被禁止! 您没有选择任何文件!");
return ERROR;
}
String path = ResourceBundle.getBundle("config").getString("site.file.upload");
path += "/user_upload/"+ DateTool.dateToStr(new java.util.Date(),"yyyyMMdd/HHmmss_");
path += (new Random().nextInt(9000)+1000)+"_";
path += user.getUsername()+upFileFileName.substring(upFileFileName.lastIndexOf("."));
SqlFile sqlFile=new FileDaoImpl().add(upFile,path,upFileFileName, user.getUsername()); //上传文件
return SUCCESS;
}
public String delete(){
User user = (User) session.get("user");
if(user==null)return LOGIN;
if(user.getIs_super()==0){
request.setAttribute("res",false);
request.setAttribute("msg","请求被禁止! 您没有权限!");
return ERROR;
}
SqlFile sf = new FileDaoImpl().findById(Integer.valueOf(request.getParameter("fid")));
if(0 == new FileDaoImpl().delete(sf)){
request.setAttribute("res",false);
request.setAttribute("msg","请求被禁止! 参数有误,请重新操作!");
return ERROR;
}
return SUCCESS;
}
public void setUpFile(File upFile) {
this.upFile = upFile;
}
public void setUpFileContentType(String upFileContentType) {
this.upFileContentType = upFileContentType;
}
public void setUpFileFileName(String upFileFileName) {
this.upFileFileName = upFileFileName;
}
@Override
public SqlFile getModel() {
return sqlFile;
}
@Override
public void setServletRequest(HttpServletRequest httpServletRequest) {
this.request =httpServletRequest;
}
@Override
public void setSession(Map<String, Object> map) {
this.session=map;
}
}
FileDaoImpl.java
该类继承了BaseDaoImpl.java,你可以根据自己的需要,把用到的函数整理到一个类中。
public class FileDaoImpl extends BaseDaoImpl<SqlFile> {
public FileDaoImpl() {
super("files");
}
/**
* 上传文件,返回path
*/
public SqlFile add(File upFile,String path,String filename){
return add(upFile,path,filename,"匿名者");
}
public SqlFile add(File upFile,String path,String filename,String username){
String realPath= ServletActionContext.getServletContext().getRealPath(path);
System.out.println("相对路径 path: "+path);
System.out.println("绝对路径realPath: "+realPath);
try {
File storeFile = new java.io.File(realPath); //创建文件
if(!storeFile.getParentFile().exists())storeFile.getParentFile().mkdirs();//父目录不存在则创建
FileUtils.copyFile(upFile, storeFile);//copy upFile ==> 磁盘文件
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件保存异常");
return null;
}
//下面在数据库中增加记录
SqlFile sqlFile=new SqlFile(); // 定义一个文件bean
sqlFile.setId(super.add()); // 增加sql记录
sqlFile.setName( filename );
sqlFile.setPath(path);
sqlFile.setUsername(username);
sqlFile.setCreated(new java.sql.Timestamp(new java.util.Date().getTime()));
super.update(sqlFile);
System.out.println("新增文件"+sqlFile);
return sqlFile;
}
public int delete(SqlFile sqlFile){
String realPath= ServletActionContext.getServletContext().getRealPath(sqlFile.getPath());
File storeFile = new java.io.File( realPath ); //创建文件
if(storeFile.isFile()){
storeFile.delete();
System.out.println("从外存中删除文件:"+sqlFile.getPath());
}
return super.delete(sqlFile);
}
}
BaseDaoImpl.java
package dao.base;
import utils.DBUtils;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
*
* @param <Bean>
* 注意: 此类实现了接口,但不可以直接调用此类投入应用,必须子类继承后,落实泛型
* 参考:https://www.cnblogs.com/RGogoing/p/5325196.html
*/
public class BaseDaoImpl<Bean> implements BaseDao<Bean> {
private Class<Bean> beanClass; // 获取实体类
private Connection conn = null;
private PreparedStatement ps = null;
private String table; //数据库表名
@SuppressWarnings("unchecked")
public BaseDaoImpl(String table) {
ParameterizedType pt=(ParameterizedType)this.getClass().getGenericSuperclass(); //泛型落实后才生效
this.beanClass=(Class<Bean>) pt.getActualTypeArguments()[0];
this.table=table;
}
@Override
public int add(){
//此函数仅插入一条空数据,并返回自增类型的id
try {
conn = DBUtils.getConnection();
ps = conn.prepareStatement("insert into "+this.table+"() values();");
ps.executeUpdate();
ps = conn.prepareStatement("select last_insert_id();");
ResultSet rs=ps.executeQuery();
while(rs.next()){
return rs.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
@Override
public int update(Bean b) {
int ret=0;
try{
Field[] fields=beanClass.getDeclaredFields(); //获取Bean类的所有字段
String sql = "update "+this.table+" set ";
for(int i=0;i<fields.length;i++) {
fields[i].setAccessible(true);
sql += fields[i].getName()+"=?" + (i<fields.length-1?",":" ");
}
sql+="where id=?";
conn = DBUtils.getConnection();
ps = conn.prepareStatement(sql);
for(int i=0,j=0;i<fields.length;i++){
fields[i].setAccessible(true);
String val=String.valueOf(fields[i].get(b));//从b对象获取了该字段的值
if(val.equals("null"))val=""; ///字符串null有点烦人,干掉
ps.setString(++j, val);
if(fields[i].getName().equals("id")){
ps.setString(fields.length+1,val);
}
}
System.out.println(ps);
ret=ps.executeUpdate();
}catch(Exception e){
e.printStackTrace();
System.out.println("[ BaseDaoImpl.update ]异常");
} finally{
DBUtils.close(null, ps, conn); //关闭数据库
}
return ret;
}
@Override
public int update(Bean b,String column) {
int ret=0;
try{
String sql = String.format("update %s set %s=? where id=?", this.table, column);
conn = DBUtils.getConnection();
ps = conn.prepareStatement(sql);
Field fieldc=beanClass.getDeclaredField(column);
Field field=beanClass.getDeclaredField("id");
fieldc.setAccessible(true);
field.setAccessible(true);
ps.setString(1, String.valueOf( fieldc.get(b) )); //本列要更新的值
ps.setString(2, String.valueOf( field.get(b) )); //id
System.out.println(ps);
ret=ps.executeUpdate();
}catch(Exception e){
e.printStackTrace();
System.out.println("[ BaseDaoImpl.update column ]异常,请检查column是否存在?");
} finally{
DBUtils.close(null, ps, conn); //关闭数据库
}
return ret;
}
@Override
public int delete(Bean b) {
String sql = "delete from "+this.table+" where id=?";
System.out.println("删除数据:"+b);
try{
conn = DBUtils.getConnection();
ps = conn.prepareStatement(sql);
Field field=beanClass.getDeclaredField("id");
field.setAccessible(true);
ps.setString(1, String.valueOf( field.get(b) ));
return ps.executeUpdate();
}catch(Exception e){
e.printStackTrace();
System.out.println("[ BaseDaoImpl.delete ]异常");
} finally{
DBUtils.close(null, ps, conn); //关闭数据库
}
return 0;
}
@Override
public Bean findById(int id) {
return findByField("id",String.valueOf(id) );
}
@Override
public Bean findByField(String column,String value) {
List<Bean> list=findAllByField(column,value);
return list.isEmpty() ? null : list.get(0);
}
@Override
public List<Bean> findAllByField(String column,String value) {
List<Bean> list=new ArrayList<>();
String sql = "select * from "+this.table+" where "+column+"=?";
try{
conn = DBUtils.getConnection();
ps = conn.prepareStatement(sql);
ps.setString(1,value);
ResultSet rs=ps.executeQuery();
Field[] fields=beanClass.getDeclaredFields(); //获取Bean类的所有字段
while(rs.next()){
if(rs.getString(column).equals(value)){
//确认匹配了再赋值,防sql注入
Bean bean=beanClass.newInstance();
for(Field field :fields){ //遍历字段
field.setAccessible(true);
field.set(bean,rs.getObject(field.getName())); //为bean的该字段赋值
}
list.add(bean);
}
}
}catch(Exception e){
e.printStackTrace();
System.out.println("[ BaseDaoImpl.findAllByField ]异常");
} finally{
DBUtils.close(null, ps, conn); //关闭数据库
}
return list;
}
@Override
public List<Bean> findAll(){
return findAll("id");
}
@Override
public List<Bean> findAll(String orderField) {
return findByPage(1,getCount(),orderField);
}
@Override
public List<Bean> findByPage(int pageNum, int pageSize, String orderField) {
//还没有排序
List<Bean> list=new ArrayList<>();
String sql = "select * from "+this.table;
if(orderField.charAt(0)=='-'){
sql+=" order by "+orderField.substring(1)+" DESC";
}else{
sql+=" order by "+orderField+" ASC";
}
sql+=" limit ?,?";
try{
conn = DBUtils.getConnection();
ps = conn.prepareStatement(sql);
ps.setInt(1, pageSize*(pageNum-1));//index begin with 0
ps.setInt(2, pageSize);
ResultSet rs=ps.executeQuery();
System.out.println(ps);
Field[] fields=beanClass.getDeclaredFields(); //获取Bean类的所有字段
while(rs.next()){
Bean bean=beanClass.newInstance(); //实例化一个bean
for(Field field :fields){ //遍历字段
field.setAccessible(true);
field.set(bean,rs.getObject(field.getName())); //为bean的该字段赋值
}
list.add(bean);
}
}catch(Exception e){
e.printStackTrace();
System.out.println("[ BaseDaoImpl.findByPage ]异常");
} finally{
DBUtils.close(null, ps, conn); //关闭数据库
}
return list;
}
@Override
public int getCount() {
try{
conn = DBUtils.getConnection();
ps = conn.prepareStatement("select COUNT(id) from "+this.table);
ResultSet rs=ps.executeQuery();
System.out.println(ps);
while(rs.next()){
return rs.getInt(1);
}
}catch(Exception e){
e.printStackTrace();
System.out.println("[ BaseDaoImpl.getCount ]异常");
} finally{
DBUtils.close(null, ps, conn); //关闭数据库
}
return 0;
}
}
DBUtils.java(数据库连接)
package utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;
/**
* 数据库操作工具类
* @author winter
* 请保证项目有包: mysql-connector-java-5.1.7-bin.jar
*/
public class DBUtils {
//数据库连接地址
public static String URL;
//用户名
public static String USERNAME;
//密码
public static String PASSWORD;
//mysql的驱动类
public static String DRIVER;
private static ResourceBundle rb = ResourceBundle.getBundle("config");
private DBUtils(){}
//使用静态块加载驱动程序
static{
URL = rb.getString("jdbc.url")+"?useUnicode=true&characterEncoding=UTF-8";
USERNAME = rb.getString("jdbc.username");
PASSWORD = rb.getString("jdbc.password");
DRIVER = rb.getString("jdbc.driver");
try {
Class.forName(DRIVER).newInstance();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
//定义一个获取数据库连接的方法
public static Connection getConnection(){
Connection conn = null;
try {
System.out.println("[ DBUtils.java ]: 正在获取数据库连接...");
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
System.out.println("[ DBUtils.java ]: 获取连接异常");
}
return conn;
}
/**
* 关闭数据库连接
* @param rs
* @param stat
* @param conn
*/
public static void close(ResultSet rs,Statement stat,Connection conn){
try {
if(rs!=null)rs.close();
if(stat!=null)stat.close();
if(conn!=null)conn.close();
System.out.println("[ DBUtils.java ]: 关闭数据库");
} catch (SQLException e) {
e.printStackTrace();
System.out.println("[ DBUtils.java ]: 关闭数据库异常");
}
}
}