(Struts2文件下载)Can not find a java.io.InputStream with the name [inputStream] in the invocation stack

本文解决了一个在使用Struts2进行文件下载时遇到的错误,该错误提示无法找到名为[inputStream]的InputStream。问题原因在于文件下载路径配置错误。通过打印流的实际路径并确保其正确性,可以解决此问题。
转载自  kaisep
最终编辑  yeyeok

2010-1-22 9:45:03 org.apache.struts2.dispatcher.StreamResult doExecute
严重: Can not find a java.io.InputStream with the name [inputStream] in the invocation stack. Check the <param name="inputName"> tag specified for this action.
2010-1-22 9:45:03 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet default threw exception
java.lang.IllegalArgumentException: Can not find a java.io.InputStream with the name [inputStream] in the invocation stack. Check the <param name="inputName"> tag specified for this action.
at org.apache.struts2.dispatcher.StreamResult.doExecute(StreamResult.java:189)
at org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:178)
at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:348)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:253)
at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:221)

==========================解决办法===========================
这个错误报的真有点误导人呀,我还一直以为我struts.xml中<param name="inputName">inputStream</param>和action中的方法名getInputStream()不一致的问题,大家如果也碰到此类问题,直接打印
InputStream in=ServletActionContext.getServletContext().getResourceAsStream(realPath);
System.out.println(in);

如果打印为NULL的话,恭喜您,问题得以解决,问题的原因是这个流的realPath路径错误,像我的,
//  String realPath=ServletActionContext.getServletContext().getRealPath("/uploadImages")+ "/"+name; 路径错误

   String realPath="/uploadImages/"+name;正确的
=====================================================
没明白的,请看下面的详细说来
怪呀,我的配置应该没错呀
页面上:
<a href="fileDownload.action?fileName=<s:property value ="imageName" />">下载此图片</a>
struts.xml中
----------------------------------------------------------
<!-- 文件下载,支持中文附件名 -->
   <action name="fileDownload"
    class="com.test.action.filedown.FileDownloadAction">
    <result name="success" type="stream">
     <!-- 动态文件下载的,事先并不知道未来的文件类型,那么我们可以把它的值设置成为:application/octet-stream;charset=ISO8859-1 ,注意一定要加入charset,否则某些时候会导致下载的文件出错; -->
     <param name="contentType">
     application/octet-stream;charset=ISO8859-1
     </param>
     <param name="contentDisposition">
      attachment;filename="${downloadFileName}"
     </param>
     <!-- 使用经过转码的文件名作为下载文件名,downloadFileName属性
      对应action类中的方法 getDownloadFileName() 其中特殊的代码就是${downloadFileName},它的效果相当于运行的时候将action对象的属性的取值动态的填充在${}中间的部分,我们可以认为它等价于+action. getDownloadFileName()。 -->
     <param name="inputName">inputStream</param>
     <param name="bufferSize">4096</param>
    </result>
   </action>
----------------------------------------------------------
action中
----------------------------------------------------------
private String fileName;// 初始的通过param指定的文件名属性 set get

/** 文件名 转换编码 防止中文乱码*/
public String getDownloadFileName() {
   String fileName=ServletActionContext.getRequest().getParameter("fileName");
   String downFileName = fileName;
   try {
    downFileName = new String(downFileName.getBytes(), "ISO8859-1");
   } catch (Exception e) {
    e.printStackTrace();
   }
   return downFileName;
}
//下载的流
public InputStream getInputStream() {
   String name=this.getDownloadFileName();
//  String realPath=ServletActionContext.getServletContext().getRealPath("/uploadImages")+ "/"+name; 路径错误
   String realPath="/uploadImages/"+name;
   InputStream in=ServletActionContext.getServletContext().getResourceAsStream(realPath);
   if(null==in){
    System.out.println("Can not find a java.io.InputStream with the name [inputStream] in the invocation stack. Check the <param name=\"inputName\"> tag specified for this action.检查action中文件下载路径是否正确.");   
   }
   return ServletActionContext.getServletContext().getResourceAsStream(realPath);
}

@Override
public String execute() throws Exception {
   return SUCCESS;
}

HTTP状态 500 - 内部服务器错误 类型 异常报告 消息 设置字段值失败 描述 服务器遇到一个意外的情况,阻止它完成请求。 例外情况 java.lang.RuntimeException: 设置字段值失败 com.yyq.util.DBUtil.setEntityField(DBUtil.java:120) com.yyq.util.DBUtil.executeQuery(DBUtil.java:78) com.yyq.dao.AdminDao.login(AdminDao.java:56) com.yyq.servlet.AdminServlet.doPost(AdminServlet.java:46) jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590) jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) 根本原因。 java.lang.NoSuchFieldException: java.lang.integer java.base/java.lang.Class.getDeclaredField(Class.java:2610) com.yyq.util.DBUtil.setEntityField(DBUtil.java:112) com.yyq.util.DBUtil.executeQuery(DBUtil.java:78) com.yyq.dao.AdminDao.login(AdminDao.java:56) com.yyq.servlet.AdminServlet.doPost(AdminServlet.java:46) jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590) jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ):注意 主要问题的全部 stack 信息可以在 server logs 里查看 Apache Tomcat/10.1.42package com.yyq.util; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.sql.*; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Properties; /** * @Author 写你的名字 * @Date 2025/9/23 下午7:07 (可以根据需要修改) * @Version 1.0 (版本号) */ public class DBUtil { private static String url ; private static String userName; private static String password; public DBUtil() { } static{ Properties properties = new Properties(); InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("db.properties"); if(is==null){ throw new RuntimeException("未找到jdbc配置文件"); } try { properties.load(is); } catch (IOException e) { throw new RuntimeException(e); } url = properties.getProperty("jdbcUrl"); userName = properties.getProperty("userName"); password = properties.getProperty("password"); } public static Connection getConnection() throws SQLException, ClassNotFoundException { Class<?> aClass = Class.forName("com.mysql.cj.jdbc.Driver"); System.out.println("mysql驱动加载成功"); return DriverManager.getConnection(url,userName,password); } public static void closeAll(Connection connection, PreparedStatement ps, ResultSet rs) throws SQLException { if(rs!=null){ rs.close(); } if(ps!=null){ ps.close(); } if(connection!=null){ connection.close(); } } public <T> List<T> executeQuery(String sql,Object[] params,Class<T> clazz) throws SQLException { Connection connection = null; PreparedStatement ps = null; ResultSet rs= null; List<T> list = new ArrayList<>(); try { connection = DBUtil.getConnection(); ps = connection.prepareStatement(sql); setParam(ps,params); rs = ps.executeQuery(); while(rs.next()){ T t = clazz.getDeclaredConstructor().newInstance(); ResultSetMetaData metaData = rs.getMetaData(); int columnCount = metaData.getColumnCount(); for (int i = 1; i <= columnCount; i++) { String columnName = metaData.getColumnClassName(i); Object value = rs.getObject(i); setEntityField(t,columnName,value); } list.add(t); } } catch (SQLException e) { throw new RuntimeException(e); } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new RuntimeException("执行查询失败",e); }finally { closeAll(connection,ps,rs); } return list; } public int executeUpdate(String sql,Object[] params) throws SQLException, ClassNotFoundException { int row = 0; Connection connection = null; PreparedStatement ps = null; ResultSet rs = null; connection = DBUtil.getConnection(); ps = connection.prepareStatement(sql); setParam(ps,params); row = ps.executeUpdate(); closeAll(connection,ps,null); return row; } private <T> void setEntityField(T t, String columnClassName, Object value) { try { String fieldName = formatColumnName(columnClassName); //获取实体类的字段 Field field = t.getClass().getDeclaredField(fieldName); //处理字段访问权限 field.setAccessible(true); //处理类型转换 Object setValue = convertValue(value,field.getType()); field.set(t,setValue); } catch (NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException("设置字段值失败" , e); } } private Object convertValue(Object value, Class<?> type) { if(value==null){ return null; } //处理日期类型转换成字符串 if(value instanceof java.util.Date && type==String.class){ java.util.Date value1 = (Date) value; return value1.toString(); } if(value instanceof Timestamp && type == String.class){ LocalDateTime localDateTime = ((Timestamp) (value)).toLocalDateTime(); String format = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); return format; } if(value instanceof Number){ if(type == Integer.class || type == int.class ){ return ((Number)value).intValue();//将number类型转换成int类型 } if(type==long.class || type == Long.class){ return ((Number)value).longValue(); } if(type==double.class || type == Double.class){ return ((Number)value).doubleValue(); } } if(type.isInstance(value)){ return value; } return value; } private void setParam(PreparedStatement ps ,Object[] param) throws SQLException { if(param!=null&&param.length>0){ for (int i = 0; i < param.length; i++) { ps.setObject(i+1,param[i]); } } } public String formatColumnName(String columnName) { if (columnName == null) { return null; } // 修复:不管是否包含下划线,都先转小写(避免数据库列名大写导致不匹配) columnName = columnName.toLowerCase(); if (!columnName.contains("_")) { return columnName; // 无下划线直接返回(如account→account) } StringBuilder sb = new StringBuilder(); String[] splitName = columnName.split("_"); sb.append(splitName[0]); // 第一部分直接加(如adminfor (int i = 1; i < splitName.length; i++) { if (splitName[i].isEmpty()) { continue; // 避免空字符串导致异常 } char c = splitName[i].charAt(0); char upperCase = Character.toUpperCase(c); // 首字母大写(如id→Id) sb.append(upperCase); sb.append(splitName[i].substring(1)); // 拼接后续字符(如d→d) } return sb.toString(); // 最终:admin_id→adminId } }
09-26
Java 中使用 `AudioInputStream` 播放音频时出现 `java.io.IOException: mark/reset not supported` 异常,通常是因为底层的 `InputStream` 不支持 `mark` 和 `reset` 操作,而 `AudioSystem.getAudioInputStream` 方法可能需要这些操作来处理音频流。解决办法是将不支持 `mark` 和 `reset` 的 `InputStream` 包装成 `BufferedInputStream`,因为 `BufferedInputStream` 支持这些操作。 以下是示例代码: ```java import javax.sound.sampled.*; import java.io.BufferedInputStream; import java.io.InputStream; public class AudioPlayer { public static void main(String[] args) { try { // 获取音频文件的输入流 InputStream inputStream = AudioPlayer.class.getClassLoader().getResourceAsStream("META-INF/resources/forklift/audio/叮咚.wav"); if (inputStream == null) { System.out.println("未找到音频文件"); return; } // 将输入流包装成 BufferedInputStream BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); // 将输入流转换为 AudioInputStream AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(bufferedInputStream); // 获取音频格式 AudioFormat format = audioInputStream.getFormat(); // 数据行信息 DataLine.Info info = new DataLine.Info(Clip.class, format); // 检查系统是否支持该数据行 if (!AudioSystem.isLineSupported(info)) { System.out.println("不支持该音频格式"); return; } // 获取 Clip 对象 Clip clip = (Clip) AudioSystem.getLine(info); // 打开音频流 clip.open(audioInputStream); // 开始播放 clip.start(); // 等待音频播放完成 Thread.sleep(clip.getMicrosecondLength() / 1000); // 关闭音频流 clip.close(); audioInputStream.close(); } catch (Exception e) { e.printStackTrace(); } } } ``` 上述代码通过将 `InputStream` 包装成 `BufferedInputStream` 解决了 `mark/reset not supported` 的问题。这种包装可以确保流支持 `mark` 和 `reset` 操作,从而避免异常的产生[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值