I've asked a question before about clean urls in java/jsp website and I got answer of it that I will need to configure my web.xml file like this
<servlet>
<servlet-name>yourjsp</servlet-name>
<jsp-file>/yourjsp.jsp</jsp-file> // here you can give jsp location
</servlet>
<servlet-mapping>
<servlet-name>yourjsp</servlet-name>
<url-pattern>/yourjsp</url-pattern>
</servlet-mapping>
So my question is that do I really have to map every URL or pattern in web.xml file?
What If I am developing a website which has USERs (NOT A SOCIAL NETWORK for GOD'S SAKE) but some type of community/forum system then I would like to use domain/UERnAME or domain/QUESTION or domain/question/what-ever-your-question-is etc, so any suggestion for that? And I want to clarify that I am still learning JAVA/JSP development and I'd like to learn it at beginner level of me.
Thank you all for helping me.
After Servlet 3.0, you don't need to use the web.xml file to map the URL to the desired resource/page.
You can do something like this:
#WebServlet("/UserController")
public class UserController extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
IOException {
RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/test.jsp");
rd.forward(request, response);
}
}
Where the URL would be http://your-domain/UserController
You can read a bit more about it here: http://java.dzone.com/articles/checking-out-what-new-servlet
Related
I'm unable to access Spring Security information during a servlet multipart post. The spring security information is available during regular get and post methods, but is not available for a multipart post method. I tried unsuccessfully to access this security information directly through SecurityContextHolder.getContext().getAuthentication() and through an injected service that accesses SecurityContextHolder.getContext().getAuthentication().
I also implemented an HttpRequestHandler and a ServletWrappingController. Once again, I was able to successuly inject spring beans into them and access Spring Security info for regular get and post methods, but I was not able access Spring Security info for a multipart posts. I know that there are new MultiPart capabilities built into Spring 3.0 but because our website will require full access to the file upload stream I won't be able to use them. For that reason, I am focusing on the HttpServlet, HttpRequestHandler and the ServletWrappingController.
The code I'm posting here is all test code written to solve this specific problem I'm facing with security information not being available during a multipart upload (not meant to be of production quality). It is for an HttpServlet.
Please let me know if there's something I'm doing wrong. Or if not, if there's a workaround or a better way to accomplish a multipart upload with access to Spring Security info while maintaining access to the file upload stream? Any assistance that someone can offer with this problem will be greatly appreciated!
Below is the test servlet code. Comments below as to what works and what doesn't is based on a user logged in to the website using Spring Security 3.1:
//many import statements not displayed
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
public class UploadServlet extends HttpServlet {
public void service(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
super.service(req, res);
}
public void init(ServletConfig config) throws ServletException {
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
config.getServletContext());
}
//The following is always injected and available
//however, it only returns valid security information for regular get and post methods,
//not for multipart post methods
#Autowired
private CustomUserService customUserService;
//The following is always injected and available and always returns the expected data
#Autowired
private GuideService guideService;
//the following does not work when the client issues a multipart post, it does work for non-multipart
public boolean getAuthenticated(){
boolean authorized = false;
for (GrantedAuthority authority : SecurityContextHolder.getContext().getAuthentication().getAuthorities()) {
if(authority.getAuthority().equals("ROLE_USER") || authority.getAuthority().equals("ROLE_ADMIN")) {
authorized = true;
break;
}
}
return authorized;
}
//The following test get method works fine
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if(getAuthenticated()){
PrintWriter out = resp.getWriter();
out.write("<h1>Guide Info</h1><br/>");
Guide guide = guideService.findById(2l);
out.write(guide.getName() + "<br/>");
out.write(guide.getDescription() + "<br/>");
out.write("UserName: " + customUserService.getCurrentUser().getUsername() + "<br/>");
}
else{
PrintWriter out = resp.getWriter();
out.write("<h1>You're not authorized</h1><br/>");
}
}
//This post method
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//the following always works, whether the clients posts using multipart or not
String guideName = guideService.findById(2l).getName();
//the following does not work when the client issues a multipart post, it does work for non-multipart
String userName = customUserService.getCurrentUser().getUsername();
//the following does not work when the client issues a multipart post, it does work for non-multipart
if(getAuthenticated()){
String responseString = RESP_SUCCESS;
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
if (isMultipart) {
ServletFileUpload upload = new ServletFileUpload();
//commmons fileupload code
// Not a multi-part MIME request.
else {
//...
}
//...
}
else{
//...
}
}
}
Here is the relevant portion of web.xml:
<servlet>
<servlet-name>fgm</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>fgm</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>UploadServlet</servlet-name>
<servlet-class>com.guides.servlet.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UploadServlet</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>
I can confirm that Spring 3.0.x and Spring Security 3.0.x together work with multipart posts as well as they work with other types of requests. I've run into similar behavior, and in our case, the security filter wasn't getting applied to the request due to our mistake in the filter mappings.
Can you post the parts of your web.xml that define the security filter, and map it to the desired paths?
This might help you, if you're using Spring MVC:
{
#RequestMapping(method = RequestMethod.POST, value = "/some/post/url")
public void postFile(MultipartHttpServletRequest request) {
MultipartFile multipartFile = request.getFileMap().get("fileControlName");
...
}
}
Security details as provided by SecurityContextHolder are (by default) stored in a ThreadLocal.
Does upload servlet creates a new thread to handle multiparts ? Try changing the SecurityContextHolderStrategy to MODE_INHERITABLETHREADLOCAL
Similar issues: How to set up Spring Security SecurityContextHolder strategy?
It might be worth checking how your client is performing the multi-part post, are you using a different mechanism/library to your standard post?
If I had to guess I would say your client code isn't authenticating correctly for the multi-part use-case.
E.g. Using standard Java for the normal post and Apache libs for the multipart post and forgetting to set the appropriate http headers when using the Apache stuff.
I've been struggling with this web xml file for Tomcat for a while.
<context-param>
<param-name>name</param-name>
<param-value>Bob</param-value>
</context-param>
<servlet>
<servlet-name>test</servlet-name>
<servlet-class>TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
I know that this file is being read because when i test using
public class TestServlet extends HttpServlet{
public void doGet(HttpServletRequest req, HttpServletResponse res){
res.setContentType("text/html");
String name = getServletContext().getInitParameter("name");
PrintWriter out = null;
try{
out = res.getWriter();
}catch(Exception e){}
out.println("<html><head></head><body><img src=\"/twitter.png\"><p>Hi my name is " + name + "</p></body></html>");
}
}
I am able to read the name I put into the context-param. My question for you guys is how do I create a URL mapping such that I do not have to go through /servlet/ to access my servlets in the URL? When I try to make a url-pattern such as
/test/*, i cannot access the servlet even if i say website/test/TestServlet. I get a 404 Not Found error from the browser
Put the servlet class in a package and do not rely on InvokerServlet. It's disabled since Tomcat 5.5 and removed in Tomcat 7.0.
Please do not read 10~15 year old tutorials/books. Technology changes every year.
See also:
How to invoke a servlet without mapping in web.xml?
To improve my java skills, I'm trying to build a simple j2ee framework (MVC).
I built it to handle every request in a FrontServlet. Here is the mapping that I used :
web.xml :
<servlet>
<servlet-name>Front</servlet-name>
<servlet-class>test.FrontServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Front</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
My problem is that when I forward the request from the FrontServlet to a JSP, obviously, the JSP request is handle by the FrontServlet and the view isn't rendered.
How can I resolve this problem by keeping the url-pattern "/*" ?
Is there a way to render a JSP in a Servlet without performance losses ?
Thanks in advance for your reply !
Solution 1 (#Bryan Kyle)
I'm trying to follow your advise. I created this filter :
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
if(!req.getRequestURL().toString().endsWith("jsp"))
{
// I changed the servlet url-pattern to "/front.controller"
req.getRequestDispatcher("/front.controller").forward(req, response);
/*chain.doFilter(req, resp);*/
}
}
<filter>
<filter-name>Filter</filter-name>
<filter-class>test.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Is it right?
Thanks !
A Filter is an inappropriate solution for a front controller approach.
You want to refine the url-pattern of your servlet so that it matches e.g. /pages/* or *.do. You don't want your front controller to kick in on irrelevant requests like CSS/JS/images/etc. To take /pages/* as an example, assuming that you've a JSP in /WEB-INF/foo.jsp, then the following in a servlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF" + request.getPathInfo() + ".jsp").forward(request, response);
}
should display the JSP in question on http://localhost:8080/contextname/pages/foo.
See also:
Design patterns in Java web applications
Hidden features of JSP/Servlet
I think the problem here might be that you're using a Servlet instead of a ServletFilter.
A ServletFilter, as the name suggests filters requests by providing pre- and post-processing on the request. You'd probably want to use a Filter if you needed to do something like the following:
Provide security checks across an entire application
Set request properties that are picked up by a servlet or jsp
Compress a response
Log timing information
Etc.
Have a look at the documentation about Servlet Filters.
I just started playing with Google App Engine and Java. I've used Servlets in the past and I understand how they work. I'm trying to make a servlet to POST to, but it's not going over very well.
Here's my Servlet:
public class CreateUser extends HttpServlet
{
private static final long serialVersionUID = 1L;
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
...
}
}
Here's what I get when I post to this from a form:
HTTP ERROR 405
Problem accessing /user/create. Reason:
HTTP method POST is not supported by this URL
I don't understand why I'm getting this when I clearly have implemented doPost. I've double and triple checked the DD (web.xml) file to make sure I have the url mappings correct. I can't find anything online specifically about this. I figure I am over looking something quite simple.
Here's my web.xml:
<web-app...>
...
<servlet>
<servlet-name>CreateUser</servlet-name>
<servlet-class>com.joelj.music.api.CreateUser</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Index</servlet-name>
<url-pattern>/user/create</url-pattern>
</servlet-mapping>
</web-app>
Thanks.
I feel really stupid. After looking at the code I just posted I realized that the entry was pointed to Index. I can't believe I over looked it so many times.
Seems like a stupid question to which the answer would be "Don't use encodeURL()!" but I'm working with a codebase that uses netui anchor tags in the JSPs and I need to disable the writing of JSESSIONID into the URLs as it is a security risk.
In WebLogic, you can configure this by configuring url-rewriting-enabled in weblogic.xml (I know because I wrote that feature in the WebLogic server!). However, I can't find an equivalent config option for Tomcat.
Tomcat 6 supports the disableURLRewriting attribute that can be set to true in your Context element:
http://tomcat.apache.org/tomcat-6.0-doc/config/context.html#Common_Attributes
No setting comes to mind. But this is fairly easy to do by creating a first-entry Filter listening on the url-pattern of interest (maybe /* ?) and replaces the ServletResponse by a HttpServletResponseWrapper implementation where the encodeURL() returns the very same argument unmodified back.
Kickoff example:
public void doFilter(ServletRequest request, ServletResponse response) throws ServletException, IOException {
chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) {
public String encodeURL(String url) {
return url;
}
});
}
As found in https://fralef.me/tomcat-disable-jsessionid-in-url.html - There is a servlet spec feature to do this
<session-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>