For Servlets to be useful, we need to read the HTTP request, and then generate a response. HTTP Servlets provide two types of instances:
HttpServletRequest
and
HttpServletResponse
.
The Servlet framework decodes the HTTP protocol parameters sent by the client into a specific map of key and values. The methods on HttpServletRequest
to access these parameters are getParameter()
, getParameterNames()
, and getParameterMap()
. The
getParameter()
method returns the first value in an array of the query string data values. This is because the HTTP standard allows an HTTP request to be formed with multiple parameter associations.
To retrieve a CGI query data in a URI, such as /fooAction?name=Mary&bus=249
, we can write a code like the following:
HttpServletRequest request = ... String name = request.getParameter("name"); int busNumber = Integer.parseInt(request.getParameter("bus"));
The Servlet framework does not allow setting of the parameters.
Every HTTP request usually has header information, which describes the client-side information relevant to the user: the invocation method, date and time, the acceptable content types, cache-control, the user agent, zero or more cookies, an optional authorization, and a whole lot more. The Servlet framework exposes through the HttpServletRequest
interface with the methods: getHeader()
, getHeaders()
, and getHeaderName()
.
Let's inspect a Servlet that demonstrates reading all the HTTP header information as follows:
@WebServlet(name = "reportHeader", urlPatterns = {"/reportHeaders"}, public class ReportHeaders extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/plain"); PrintWriter pwriter = resp.getWriter(); pwriter.printf("Header information: "); for (String name: Collections.list(req.getHeaderNames())) { pwriter.printf("%s = %s ", name,req.getHeader(name)); } } }
The ReportHeader
servlet iterates through all of the headers with getHeaders()
, which returns Enumeration<String>
, and then we use the Java Collection framework to manipulate this type into List<String>
. For each key in the collection, we dump the header to the Servlet's response writer.
The request attributes are objects that are associated with the HTTP request, hence they are scoped. The request attributes only live for the lifetime of processing a request through the Servlet framework. The attributes are removed after the response has been sent back to the client. If you remember from Chapter 2, Context and Dependency Injection, this request scope is the reason why there is a @RequestScoped
annotation for the bean types.
The request attributes are available on HttpServletRequest
with the methods getAttribute()
, getAttributeNames()
, and setAttribute()
. The attributes are useful for passing the attributes from one Servlet instance. The Servlet framework provides a RequestDispatcher
instance to forward a request on to another or include the content from another Servlet.
The following is an example of a Servlet that geolocates a city to a dealer. This use case is a car manufacturer's business:
@WebServlet(name = "carProduct", urlPatterns = {"/carProduct"}, public class CarProduct extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String city = req.getParameter("city") req.setAttribute("dealerId", findNearestDealerFromCity(city)); RequestDispatcher rd = req.getDispatcher("/viewDealer") rd.forward(req,resp); } }
The CarProduct
Servlet sets a request scope attribute dealerId
with the value obtained from the CGI query parameter city
. There is a method findNearestDealerFromCity()
, we assume, that handles the geolocation search for us. The
doGet()
method obtains a RequestDispatcher
instance from HttpServletRequest
, and forwards it to the next Servlet named viewDealer
.
Let's review the code for the ViewDealer
Servlet as follows:
@WebServlet(name = "viewDealer", urlPatterns = {"/viewDealer"}, public class ViewDealer extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String dealerId = (String)req.getAttribute("dealerId"); /* ... */ generateContent(req, resp, dealerId); } }
The subsequent Servlet is able to retrieve the request scope attribute dealerId
, and generate the content around this information.
The Servlet framework provides a means to track the requests that emanate from the same device that is operated by a user. Because of the stateless nature of HTTP, the framework associates similar request from the same client and user in either an HTTP cookie or through URL rewriting. For Servlet containers that support HTTPS protocol connections, the Servlet framework will use standard SSL handshake with encrypted key exchange.
A Servlet session has a lifecycle, which is unique to an HTTP client device, and it is a means for data to survive multiple requests to the Servlet container. A session is a scope and a collection name and value attributes. The Servlet sessions can optionally time out with expiration, and if the session does expire, then the servlet container will remove the information.
The session attributes are available in the
HttpSession
instance with the methods getAttribute()
, setAttribute()
, and getAttributeNames()
. The
HttpSession
instance acquired from the HttpServletRequest
object is like the following code:
HttpServletRequest request = ... HttpSession session = request.getSession(); CustomerData custData = (CustomerData) session.getAttribute("customerData"); session.setAttribute("checkoutInfo", "PRIVILEGED");
As with the request scope attribute, we have to cast to a String
on the getAttribute()
method, because this call returns an Object
. The session scope is closely aligned with the CDI @SessionScoped
annotation.
Every Java Servlet has an association to ServletContext
, which is shared between all Servlets in the web application. The specification declares a rule: there is one context per web application per JVM. ServletContext
is an ideal place to share a cache of read-only values that are used for the entire lifecycle of the application.
In the JSF, JSP, and CDI specifications, ServletContext
is known as the application scope. The CDI @ApplicationScoped
corresponds with this unique instance. The key methods for the ServletContext
interfaces are getAttribute()
, setAttribute()
, and getAttributeNames()
.
Here is a small illustration of the application-wide Servlet loading static data, which is supposed to be read-only. ServletContextDemo
is as follows:
@WebServlet(name = "servletContextDemo", urlPatterns = {"/servletContextDemo"}, public class ServletContextDemo extends HttpServlet { @Override public void init(ServletConfig config) { config.getServletContext() .setAttribute("dataValues", Arrays.asList(1,2,3,5,8,13,21,34,55,89)); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/plain"); PrintWriter pwriter = resp.getWriter(); List<Integer> series = (List<Integer>)getServletContext() .getAttribute("dataValues"); pwriter.printf("series=%s ", series); } }
During initialization of ServletContextDemo
, we store the Fibonacci series as an integer collection inside ServletContext
, which we can access from the ServletConfig
instance. When the user invokes HTTP GET on this Servlet, we retrieve the data series from ServletContext
, and send its contents as the response. Inside the doGet()
method, we access ServletContext
from HttpServletRequest
.
There are occasions in a web application where the response must be redirected to another location. The Servlet framework sends an HTTP URL redirection to the client (web browser) with a URL that informs where to get the content. We can write the Servlet code to do that as follows:
HttpServletResponse httpServletResponse = httpServletResponse.sendRedirect(httpServletResponse.encodeRedirectURL(httpServletRequest.getContextPath()+ "/carProduct"));
This code extraction redirects the client to the earlier CarProduct
Servlet. Because URL redirects can go to any site on the Internet, for example, http://www.bbc.co.uk/news, we must add the web application context path to the URI. After issuing a redirect, the HttpServletResponse
instance will be in an undefined state. It is a good practice to encode the URL path with the convenience call encodeRedirectURL()
.
Many developers apply the technique of POST-REDIRECT-GET
. This design pattern effectively avoids returning a rendered web page directly for an incoming request and instead instructs the web browser to load a different the page with a follow up HTTP GET request.. This is an advanced technique out-of-scope for discussion in this book.
3.143.239.103