You're basically looking in the wrong direction for the solution. And, you're looking at JSF/PrimeFaces in a wrong way. JSF is in the context of this question just a HTML code generator.
HTML does not support sending full client side file path to the server side. True, older Internet Explorer versions had the awkward security bug that the full client side file path was sent along the file name. But, this is not mandated by HTML. The sole purpose of <input type="file">
is to send the file content from client to server, which you're supposed to read via getInputStream()
and save on a fixed location yourself. The filename is here just additional metadata. This is usually never used as-is to save the file in the server, to avoid overwrites by other uploads with coincidentally the same filename. The file name is at most used as prefix of the final file name in the server side, or only remembered in order to be redisplayed in "Save As" during a download. But that's it.
All your attempts failed because here,
File file = new File(uploadedFile.getFileName());
System.out.println(file.getAbsolutePath());
.. the getFileName()
only returns the file name, not the file path. The new File(...)
constructor will interpret the file name relative to the "current working directory", i.e. the directory which was open at the moment the JVM (in your case, the server), was started. Basically, you're attempting to locate a non-existing file. The actual file is stored elsewhere, usually in the OS-managed temporary file location beyond your control. However, this is also not what you're looking for.
And here,
String realPath = FacesContext.getCurrentInstance().getExternalContext().getRealPath("/");
System.out.println(realPath);
.. the getRealPath()
only converts the webcontent-relative path to absolute disk file system path. In other words, it gives you the path to the deploy folder where all contents of the expanded WAR file are stored. Usually it are the XHTML/JS/CSS files and such. This is also definitely not what you're looking for. Moreover, there is no single sensible real world use case for getRealPath()
. You should absolutely avoid using it.
You need to look for the solution in a different direction than HTML. You need a client side application capable of grabbing the full client side file path and then sending it to the server side. HTML can't do it (even not HTML5). CSS can't do it. JS can't do it. But Java can do it. You can use Swing JFileChooser
to browse and pick the actual File
. You only need to execute it in the client side instead of the server side. You can use an Applet for this which you in turn can easily embed in any webpage, even a JSF page; you know, it's just a HTML code generator.
Basically:
In applet, grab full file path via JFileChooser
.
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
File selectedFile = fileChooser.getSelectedFile();
String selectedFileAbsolutePath = selectedFile.getAbsolutePath();
// ...
} else {
// User pressed cancel.
}
Additional advantage is, you can use FileSystemView
to restrict it to certain (network) drives or folders, so that the enduser won't accidentally select completely irrelevant drives/folders.
Send the full file path as query parameter via URLConnection
to server side.
String url = "/someServletURL?selectedFileAbsolutePath=" + URLDecoder.decode(selectedFileAbsolutePath, "UTF-8");
URLConnection connection = new URL(getCodeBase(), url).openConnection();
connection.setRequestProperty("Cookie", "JSESSIONID=" + getParameter("sessionId"));
InputStream response = connection.getInputStream();
// ...
Read it in a servlet.
@WebServlet("/someServletURL")
public class SomeServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse resposne) throws ServletException, IOException {
String selectedFileAbsolutePath = request.getParameter("selectedFileAbsolutePath");
// ...
}
}
Don't forget to pass session ID as applet parameter when embedding the applet in JSF page.
<applet ...>
<param name="sessionId" value="#{session.id}" />
</applet>
This way the servlet will have access to exactly the same HTTP session as the JSF page, and then you can share/communicate data between them.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…