What we do is to put it in a separate directory on the server (you could use something like /config, /opt/config, /root/config, /home/username/config, or anything you want). When our servlets start up, they read the XML file, get a few things out of it (most importantly DB connection information), and that's it.
I asked about why we did this once.
It would be nice to store everything in the DB, but obviously you can't store DB connection information in the DB.
You could hardcode things in the code, but that's ugly for many reasons. If the info ever has to change you have to rebuild the code and redeploy. If someone gets a copy of your code or your WAR file they would then get that information.
Putting things in the WAR file seems nice, but if you want to change things much it could be a bad idea. The problem is that if you have to change the information, then next time you redeploy it will overwrite the file so anything you didn't remember to change in the version getting built into the WAR gets forgotten.
The file in a special place on the file system thing works quite well for us. It doesn't have any big downsides. You know where it is, it's stored seperatly, makes deploying to multiple machines easy if they all need different config values (since it's not part of the WAR).
The only other solution I can think of that would work well would be keeping everything in the DB except the DB login info. That would come from Java system properties that are retrieved through the JVM. This the Preferences API thing mentioned by Hans Doggen above. I don't think it was around when our application was first developed, if it was it wasn't used.
As for the path for accessing the configuration file, it's just a file on the filesystem. You don't need to worry about the web path. So when your servlet starts up it just opens the file at "/config/myapp/config.xml" (or whatever) and it will find the right thing. Just hardcodeing the path in for this one seems pretty harmless to me.
I came up with a slightly different solution. It's a bit hack-ish, but here is the mapping:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>myAppServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
This basically just maps all content files by extension to the default servlet, and everything else to "myAppServlet".
It works in both Jetty and Tomcat.
Best Answer
If you adhere the *nix filesystem path rules (i.e. you use exclusively forward slashes as in
/path/to/files
), then it will work on Windows as well without the need to fiddle around with uglyFile.separator
string-concatenations. It would however only be scanned on the same working disk as from where this command is been invoked. So if Tomcat is for example installed onC:
then the/path/to/files
would actually point toC:\path\to\files
.If the files are all located outside the webapp, and you want to have Tomcat's
DefaultServlet
to handle them, then all you basically need to do in Tomcat is to add the following Context element to/conf/server.xml
inside<Host>
tag:This way they'll be accessible through
http://example.com/files/...
. For Tomcat-based servers such as JBoss EAP 6.x or older, the approach is basically the same, see also here. GlassFish/Payara configuration example can be found here and WildFly configuration example can be found here.If you want to have control over reading/writing files yourself, then you need to create a
Servlet
for this which basically just gets anInputStream
of the file in flavor of for exampleFileInputStream
and writes it to theOutputStream
of theHttpServletResponse
.On the response, you should set the
Content-Type
header so that the client knows which application to associate with the provided file. And, you should set theContent-Length
header so that the client can calculate the download progress, otherwise it will be unknown. And, you should set theContent-Disposition
header toattachment
if you want a Save As dialog, otherwise the client will attempt to display it inline. Finally just write the file content to the response output stream.Here's a basic example of such a servlet:
When mapped on an
url-pattern
of for example/files/*
, then you can call it byhttp://example.com/files/image.png
. This way you can have more control over the requests than theDefaultServlet
does, such as providing a default image (i.e.if (!file.exists()) file = new File("/path/to/files", "404.gif")
or so). Also using therequest.getPathInfo()
is preferred aboverequest.getParameter()
because it is more SEO friendly and otherwise IE won't pick the correct filename during Save As.You can reuse the same logic for serving files from database. Simply replace
new FileInputStream()
byResultSet#getInputStream()
.Hope this helps.
See also: