java struts2文件上传

初次整理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文件限制

[参考文章]: https://www.cnblogs.com/itmyhome/p/4131231.html

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 ]: 关闭数据库异常");
        }
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪的期许

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值