使用Servlet上传图片后文件损坏无法打开,寻求问题排查与解决方法
问题根因
- 输入流读取逻辑错误:你已经通过
req.getPart("image")拿到了上传的图片分片,此时调用req.getInputStream()读取的是整个multipart请求的原始数据流,包含表单字段、分隔符等非图片内容,不是纯净的图片二进制数据。 InputStream.available()方法使用错误:该方法仅返回当前可无阻塞读取的字节数,不能代表整个流的总长度,会导致读取的字节不完整,直接造成文件截断损坏。- 路径转义错误:Java字符串中反斜杠是转义字符,直接写
D:\FullstackWeb\images\icon\会被识别为转义序列,实际生成的路径不符合预期。 - 流资源未正确关闭:文件输出流写入完成后没有关闭,可能导致缓冲区数据未完全写入磁盘,造成文件损坏。
- 数据库存储路径不合理:直接存储本地磁盘绝对路径到数据库,后续前端无法直接访问该路径下的图片,建议改为存储相对应用的访问路径或者静态资源映射路径。
修正后代码
public class Register extends HttpServlet{ @Override protected void doPost(HttpServletRequest req,HttpServletResponse res) throws ServletException,IOException{ String username=req.getParameter("username"); String password=req.getParameter("password"); String email=req.getParameter("email"); Part part = req.getPart("image"); String filename = part.getSubmittedFileName(); // 修正路径转义,双反斜杠才会被识别为路径分隔符 String path = "D:\\FullstackWeb\\images\\icon\\"+filename; System.out.println(path); // 从part中读取纯净的图片流,用try-with-resources自动关闭流资源 try(InputStream is = part.getInputStream(); FileOutputStream fos=new FileOutputStream(path)){ // 用缓冲分段读取,避免available()的缺陷 byte[] buffer = new byte[1024]; int len; while((len = is.read(buffer)) != -1){ fos.write(buffer, 0, len); } } res.setContentType("text/html;charset=utf-8"); PrintWriter out = res.getWriter(); try { Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://dns1.nishchay.com:3306/register","demouser","123Nbr@"); // 建议此处修改为存储相对路径,比如"/images/icon/"+filename,后续配置静态资源映射即可直接访问图片 String query = "Insert INTO register.signup(username,email,userpassword,filename) values(? ,?, ?,?)"; PreparedStatement pstmt= conn.prepareStatement(query); pstmt.setString(1, username); pstmt.setString(2, email); pstmt.setString(3, password); pstmt.setString(4, path); pstmt.executeUpdate(); conn.close(); }catch(Exception e) { out.println("<h1>出现错误</h1>"); } } }
内容的提问来源于stack exchange,提问作者nischit
相关产品推荐
相关产品推荐

