I'm working on my first web project using tomcat, jsp, servlets and log4j and I have a demo of using Command design pattern, which I'm interested in. I have one Controller which accepts doGet and doPost methods and then proccesses requests to CommandContainer which finds appropriate Command, executes it, gets path to resource and forwards the client to it.
public abstract class Command implements Serializable {
private static final long serialVersionUID = 8879403039606311780L;
public abstract String execute(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException;
}
CommandContainer which manages Commands:
public class CommandContainer {
private static final Logger LOG = Logger.getLogger(CommandContainer.class);
private static Map<String, Command> commands = new TreeMap<String, Command>();
static {
// common commands
commands.put("login", new LoginCommand());
commands.put("logout", new LogoutCommand());
commands.put("viewSettings", new ViewSettingsCommand());
commands.put("noCommand", new NoCommand());
// client commands
commands.put("listMenu", new ListMenuCommand());
// admin commands
commands.put("listOrders", new ListOrdersCommand());
LOG.debug("Command container was successfully initialized");
LOG.trace("Number of commands --> " + commands.size());
}
public static Command get(String commandName) {
if (commandName == null || !commands.containsKey(commandName)) {
LOG.trace("Command not found, name --> " + commandName);
return commands.get("noCommand");
}
return commands.get(commandName);
}
The only Controller I have:
public class Controller extends HttpServlet {
private static final long serialVersionUID = 2423353715955164816L;
private static final Logger LOG = Logger.getLogger(Controller.class);
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
process(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
process(request, response);
}
private void process(HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
LOG.debug("Controller starts");
// extract command name from the request
String commandName = request.getParameter("command");
LOG.trace("Request parameter: command --> " + commandName);
// obtain command object by its name
Command command = CommandContainer.get(commandName);
LOG.trace("Obtained command --> " + command);
// execute command and get forward address
String forward = command.execute(request, response);
LOG.trace("Forward address --> " + forward);
LOG.debug("Controller finished, now go to forward address --> " + forward);
// if the forward address is not null go to the address
if (forward != null) {
RequestDispatcher disp = request.getRequestDispatcher(forward);
disp.forward(request, response);
}
}
}
I'am using Controller in jsp in the next way:
...
<form id="login_form" action="controller" method="post">
<input type="hidden" name="command" value="login"/>
...
</form>
And web.xml file:
<servlet>
<servlet-name>Controller</servlet-name>
<servlet-class>com.mycompany.web.Controller</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Controller</servlet-name>
<url-pattern>/controller</url-pattern>
</servlet-mapping>
I don't understand how to implement Post-Redirect-Get pattern with Command pattern, because every time request comes to controller it uses process() method and seems that it doesnt matter GET or POST is used in JSP. And then would you help understand the need of use Command pattern ? What if I will use multiple servlets like LoginServlet, LogoutServlet, ViewSettingsServlet instead of one Controller - is it would be a bad idea because then I need to hardcode them in jsp forms as actions ? All this questions just confusing me, cos I'm a starter, so please jelp me understand all this.
Well, currently, your command returns a String: the name of the JSP to forward to. If I understand correctly, you also want to be able to redirect instead of forwarding. So you need to tel the servlet that the returned value if not a view name to forward to, but a URL to redirect to.
There are various ways to do that. You could for example return an object containing the type of action to do (FORWARD or REDIRECT), and the view name or URL. Or you could return a String like redirect:/foo/bar, which means that /foo/bar is a URL to redirect to, and not a view name.
But the best solution would probably to avoid reinventing the wheel, and use an existing MVC framework rather than implementing one yourself: Spring MVC, Stripes, Struts, etc. all provide much more than what you have there, and in a much better way. In particular, using a request parameter to choose the command is not a very good choice. Using the path is a much better idea.
You could also simply use multiple servlets, which would be better than your current solution. You would lose the front controller though, which typically contains code that is common to all commands: internationalization, security checks, etc.
Related
I want to call an method from an object in jsp.
I have an servlet which passes an object to a jsp page. On this page I want to execute the getHtml() method. How do I accomplish this?
Servlet
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
...
MyClass myObject = new MyClass();
response.setAttribute(myObject, "myObject");
RequestDispatcher rd = request.getRequestDispatcher("/index.jsp");
rd.forward(request, response);
}
MyClass
public class MyClass {
public String getHtml() {
return "<p>Hello World</p>";
}
}
You may do:
<div>${myObject.getHtml()}</div>
As it is a property and with the get prefix you may also do:
<div>${myObject.html}</div>
Or this way to scape HTML characters to avoid cross-site scripting:
<div><c:out value="${myObject.hHtml}"/></div>
All this ways assume that those methods return a String. If you need a piece of dynamic HTML it is OK. If you are doing some business logic in JSP it would be looked as a potencial bad practice. Try to put as much logic as possible in the controller or service and get the results preprocessed as properties or use jsp tags. At some point the html of the jsp will need to change or you would have used html instead.
I'm restricted to work on an enterprise software project using Netbeans IDE, and no frameworks.
The front-end display is register.jsp. My Model package contains Customer.java class, with some getters and setters. A Data package contains 'CustomerData.java', with DB functions related to the Customer: registration, log-in, etc. CustomerData extends HttpServlet.
I need to reference a specific method from the CustomerData class from my registration form. Is this possible to do?
If this is possible to do, what should the web.xml file entry be for the servlet and servletmapping?
Here is code.
Register.jsp
<form name="loginForm" method="post" action="CustomerData/RegisterCustomer">
......
</form>
CustomerData.java skeleton:
public class CustomerData extends HttpServlet {
public void registerCustomer(HttpServletRequest request)
throws ServletException, IOException
{
// this is the method I need to reference. It creates a db connection, checks to see if
// the Customer is already in the DB, and if not, registers the user.
}
public void loginCustomer(HTTPServlet request)
throws ServletException, IOException
{
// Some other Customer data method that will need to be called from my login.jsp page
}
public void SomeOtherMethod()
{
// some helper methods or validation methods for Customer
}
}
I would recommend you the below thing.
In the JSP page you can define one parameter say opr where you can set value of the operation.
<form name="loginForm" method="post" action="CustomerData/">
<input type=hidden name=opr id=opr value=1
......
</form>
In the Servlet you can handle the operation by the operation value passed as below
public doPost(HttpServletRequest req, HttpServletResponse res){
int operation = Integer.valueOf(req.getParameter("opr"));
if (operation == 1){
registerCustomer(req);
}else if (operation == 2){
loginCustomer(req);
}else if (operation == 3){
SomeOtherMethod();
}...
}
Hope this will help you.
What you want to do can be done by using getPathInfo
Assuming your servlet mapping is
<servlet-mapping>
<servlet-name>CustomerData</servlet-name>
<url-pattern>/CustomerData/*</url-pattern>
</servlet-mapping>
Calling
String pathInfo = request.getPathInfo();
will give you the value '/RegisterCustomer' in pathInfo. From there it should be rather trivial to figure out what method needs to be called. Don't forget to ad check code to deal with all kinds of abuse that might be thrown at the servlet (eg no "method name" is given, nonexisting method names are specified, etc).
my task is to check if my program is running fine on server or not.The scenario is like this :A URL is sent to the program that is continuously running and it is supposed to reply with a status OK if it is running fine.I am not able to understand the process how to do it.Can anyone explain.
OK, I am assuming that you wanted to write some sort of health check page for your application. So here it goes.
package test.naishe.so;
public class HealthCheck extends HttpServlet {
private static final long serialVersionUID = 940861886429788526L;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
int response = HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
boolean checkServices = true;
//optional: assumming you wanted to do health check on various services (eg. DB service) and have a utility class for that
checkServices = CheckServices.checkAll();
if(checkServices)
response = HttpServletResponse.SC_OK;
String out =
"<healthCheck>" +
"<services>" +
(checkServices?"OK":"ERROR")
"</services>" +
"</healthCheck>"
;
resp.setStatus(response);
resp.getWriter().println(out);
}
}
in your web.xml add the following:
<servlet>
<servlet-name>healthCheck</servlet-name>
<servlet-class>test.naishe.so.HealthCheck</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>healthCheck</servlet-name>
<url-pattern>/check_health</url-pattern>
</servlet-mapping>
you can access this page from <base_url>/check_health on your local machine, http://localhost[:port][/app_name]/check_health
I have a JSP page which has nothing but a normal HTML table with five rows and five columns.
Now I am making an Ajax call and get a response back. Now once I have the response back, I need the data to be filled in appropriate cells of the table.
So my question is;
Should I use JSON for building the response?
How do I handle the data back at the JSP level. That is, once I have the response from the server?
Just as additional information, I am using DWR which is nothing but calling a Java method (which builds the response) from inside JavaScript code.
Let's consider this Java class.
class Employee
{
int id;
String eName;
// Setters and getters
}
In JavaScript, the JSON object:
var employee = {
id : null,
name : null
};
This is the call to a Java method from a JavaScript function:
EmployeeUtil.getRow(employee,dwrData);
In getRow() of the EmployeeUtil class, the return type of method will be Employee:
Employee getRow();
So using the setters of Employee set the data. dwrData is the callback function.
function dwrData(data) {
employee=data;
}
The data returned, which is an Employee bean, will be in the callback function.
Just initialize this in the JavaScript JSON object.
Use a JSON object accordingly to populate the table.
EDIT :
You can use List getRow() instead of Employee getRow(), returning a list of rows as a List instead of a Bean.
Now the response contains list as data.
Refer to Populate rows using DWR.
Check these examples to populate data in table:
DWR + Dojo Demo
Dynamically Editing a Table
Should I use JSON for building the response?
No need to pass JSON in response. Instead return a Bean of a class as mentioned above.
A list can be passed as a response, also as mentioned above.
How do I handle the data back at the JSP level. That is, once I have the response from the server.
Check the explanation above and the examples of the given links to handle the response in JSP and display the response data in a table.
DWR basics on YouTube
JSP pages are dynamically generated servlets. Once a user hits a JSP page, they receive dynamically generated HTML that no longer talks to the JSP page that generated it unless they complete an action such as hitting "refresh" or submitting a form. Check out the JSP Page at Oracle for more info and Wikipedia for a decent high level explanation of JSP technology.
To handle the AJAX, you're going to need to define a new network endpoint capable of processing the XML requests coming up from the Javascript. See this example, this library, or this JSON Example.
What I do quite frequently is setup two servlets for this situation:
MyServlet
MyAJAXServlet
MyServlet handles the normal HTTP requests and (usually) ends up using a RequestDispatcher to forward the request to a JSP.
Example:
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = -5630346476575695999L;
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doGetAndPost(req, res);
}
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doGetAndPost(req, res);
}
private final void doGetAndPost(HttpServletRequest req,
HttpServletResponse res) throws ServletException, IOException {
/*
* Handle the response here, manipulate the 'MODEL'
*/
/*
* Forward to the 'VIEW' (No Baba Wawa jokes please)
*/
RequestDispatcher rdis = req.getRequestDispatcher("Path/To/My/JSP");
rdis.forward(req, res);
}
}
Where as the AJAX servlet checks the request's parameter list for presence of a 'command':
public class MyAJAXServlet extends HttpServlet {
private static final long serialVersionUID = -5630346476575695915L;
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doGetAndPost(req, res);
}
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
doGetAndPost(req, res);
}
private final void doGetAndPost(HttpServletRequest req,
HttpServletResponse res) throws ServletException, IOException {
String cmd = req.getParameter("cmd");
if (cmd == null || cmd.length() < 1) {
/* Custom fail mode here, perhaps toss back failure HTML */
return;
}
/* Easily implement command pattern here, but for simplicity, we will use an if tree */
if (cmd.equalsIgnoreCase("getSomeData")) {
String out = "<tr><td>ExampleCell in ExampleRow</td></tr>";
res.getWriter().append(out);
return;
} else if (cmd.equalsIgnoreCase("someOtherCommand")) {
/* Do something else */
}
}
}
If you format your JSP to allow for bulk replacement of html elements like so:
<table id="pleaseReplaceMyContentsTABLE">
<tr><td> </td></tr>
</table>
Then it becomes very easy to dynamically modify a web pages content (I use JQuery for this example):
var url = "http://mydomain.whatever/myapp/MyAJAXServletMappedURL?cmd=getSomeData";
$.post(url, function(data) {
//Message data a bit & display
$("#pleaseReplaceMyContentsTABLE").html(data);
});
Some limitations with sending back preformatted HTML from the AJAX Servlet:
If you are sending back a moderate to large amount of data, then your webserver will easily become overloaded when the number of clients starts to rise. Aka, it won't scale well.
Java code that is formatting HTML to send to a client can get ugly and hard to read. Quickly.
If you use DWR you don't need to use JSON, it uses internally.
Use javascript , the jsp code is out-of-scope. The page has been generated so you only can modify the DOM using javascrip
There are lot of examples doing what you need in DWR tutorials. I suppose you need just do something as:
dwrobject.funtionAjax(param,returnFunction);
...
function returnFunction(data) {
// use javascript to change the dom
}
Ajax part: We return a list of objects:
public List<IdTexto> getPaisesStartingBy(String texto,String locale){
List<IdTexto> res = new ArrayList<IdTexto>();
// Fill the array
return res;
}
The IdTexto is a simple bean with geters and setters:
public class IdTexto {
private int id;
private String texto;
private String texto2;
// getters and setters
}
And it is defined in the dwr.xml as bean:
<convert converter="bean" match="com.me.company.beans.IdTexto"/>
And the class containing the java function is defined as creator:
<create creator="new" javascript="shopdb">
<param name="class" value="com.me.company.ajax.ShopAjax"/>
</create>
In the jsp, we define a function javascript to retrieve the List of starting by some text object in this way:
shopdb.getPaisesStartingBy(req.term,'<s:text name="locale.language"/>', writePaises);
And the corresponding function to write down the texts:
function writePaides (data) {
var result="<table>";
for (i=0; i<data.length;i++) {
id = data[i].id;
texto=data[i].texto;
texto2=data[i].txto2;
// now we write inside some object in the dom
result+="<tr><td>"+id+"</td><td>"+texto+"</td><td>"+texto2+"</td></tr>";
}
result+="</table>";
$("tabla").innerHTML=result;
}
If you, instead of a bean have some other object you'll access the properties in the same way.
Hello I've been trying to figure out generic way to log http requests in my application, so far no luck, here is how I handle the logging right now i.e:
#RequestMapping(value="register", method = RequestMethod.POST)
#ResponseBody
public String register(#RequestParam(value="param1",required=false) String param1, #RequestParam("param2") String param2, #RequestParam("param3") String param3, HttpServletRequest request){
long start = System.currentTimeMillis();
logger.info("!--REQUEST START--!");
logger.info("Request URL: " + request.getRequestURL().toString());
List<String> requestParameterNames = Collections.list((Enumeration<String>)request.getParameterNames());
logger.info("Parameter number: " + requestParameterNames.size());
for (String parameterName : requestParameterNames){
logger.info("Parameter name: " + parameterName + " - Parameter value: " + request.getParameter(parameterName));
}
//Some processing logic, call to the various services/methods with different parameters, response is always String(Json)
String response = service.callSomeServiceMethods(param1,param2,param3);
logger.info("Response is: " + response);
long end = System.currentTimeMillis();
logger.info("Requested completed in: " + (end-start) + "ms");
logger.info("!--REQUEST END--!");
return response;
}
So what I do right now for different controllers/methods is copy everything from beginning of the inside of the method until the processing logic which differs from method to method and then copy everything from below of that as showed in above template.
It is kind of messy, and there is a lot of code repetition(which I don't like). But I need to log everything.
Does anyone have more experience with this kinds of logging, can anyone shed some light on this?
EDIT: Also, see #membersound's comment on this answer, which improves this answer.
Spring supports this. See CommonsRequestLoggingFilter. If using Spring Boot, just register a bean of that type and Boot will apply it to the filter chain. Like:
#Bean
public Filter logFilter() {
CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
filter.setIncludeQueryString(true);
filter.setIncludePayload(true);
filter.setMaxPayloadLength(5120);
return filter;
}
Also, this logging filter requires the log level be set to DEBUG. E.g. do this in a logback.xml with:
<logger name="org.springframework.web.filter.CommonsRequestLoggingFilter" level="DEBUG"/>
Use an interceptor:
extend HandlerInterceptorAdapter and override preHandle
define it with <mvc:interceptors> in dispatcher-servlet.xml
It will run for every request.
The main issue with reading request is that as soon as the input stream is consumed its gone whoof... and cannot be read again. So the input stream has to be cached. Instead of writing your own classes for caching (which can be found at several places on web), Spring provides a couple of useful classes i.e. ContentCachingRequestWrapper and ContentCachingResponseWrapper. These classes can be utilized very effectively, for example, in filters for logging purposes.
Define a filter in web.xml:
<filter>
<filter-name>loggingFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>loggingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Since the filter is declared as DelegatingFilterProxy, it can be declared as a bean using #Component or #Bean annotations. In the loggingFilter's doFilter method, wrap the request and response with spring provided classes before passing it to the filter chain:
HttpServletRequest requestToCache = new ContentCachingRequestWrapper(request);
HttpServletResponse responseToCache = new ContentCachingResponseWrapper(response);
chain.doFilter(requestToCache, responseToCache);
String requestData = getRequestData(requestToCache);
String responseData = getResponseData(responseToCache);
The input stream will be cached in the wrapped request as soon as the input stream is consumed after chain.doFilter(). Then it can be accessed as below:
public static String getRequestData(final HttpServletRequest request) throws UnsupportedEncodingException {
String payload = null;
ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
if (wrapper != null) {
byte[] buf = wrapper.getContentAsByteArray();
if (buf.length > 0) {
payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
}
}
return payload;
}
However, things are a bit different for response. Since the response was also wrapped before passing it to the filter chain, it will also be cached to the output stream as soon as it is written on its way back. But since the output stream will also be consumed so you have to copy the response back to the output stream using wrapper.copyBodyToResponse(). See below:
public static String getResponseData(final HttpServletResponse response) throws IOException {
String payload = null;
ContentCachingResponseWrapper wrapper =
WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
if (wrapper != null) {
byte[] buf = wrapper.getContentAsByteArray();
if (buf.length > 0) {
payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
wrapper.copyBodyToResponse();
}
}
return payload;
}
Hope it helps!
Here's a small library I wrote you can use: spring-mvc-logger
I made it available via maven central:
<dependency>
<groupId>com.github.isrsal</groupId>
<artifactId>spring-mvc-logger</artifactId>
<version>0.2</version>
</dependency>
Adding to what #B.Ali has answered. If you are using this in a spring asynchronous request (serlvet 3.0 or greater) handling scenario, then the following code is what worked for me.
public class OncePerRequestLoggingFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
boolean isFirstRequest = !isAsyncDispatch(request);
HttpServletRequest requestToUse = request;
HttpServletResponse responseToUse = response;
// The below check is critical and if not there, then the request/response gets corrupted.
// Probably because in async case the filter is invoked multiple times.
if (isFirstRequest && !(request instanceof ContentCachingRequestWrapper)) {
requestToUse = new ContentCachingRequestWrapper(request);
}
if (isFirstRequest && !(response instanceof ContentCachingResponseWrapper)) {
responseToUse = new ContentCachingResponseWrapper(response);
}
filterChain.doFilter(requestToUse, responseToUse);
if (!isAsyncStarted(request)) {
ContentCachingResponseWrapper responseWrapper =
WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
responseWrapper.copyBodyToResponse(); // IMPORTANT to copy it back to response
}
}
#Override
protected boolean shouldNotFilterAsyncDispatch() {
return false; // IMPORTANT this is true by default and wont work in async scenario.
}
}
As any tech answer ... it depends ..
on the tech stack you are using and what your requirements are.
for example the more generic you want to make your logging, the further upfront you would want to do it. in your case, you are logging only requests which are logging enabled and being handled in the spring context. So you could be "missing" other requests.
I would look at the container or the web server you are using to run your app. That will remove this dependency on Spring. Plus containers provide you the flexibility of plugging in a logging provider and then configuring the format of the log outside code.
For example, if you are using Apache Web server, use Apache web server logging to log all HTTP requests in the access logging layer. But be careful, some of the logging options have performance penalties. Log only what you seriously need for an access pattern monitoring perspective.
If you are using tomcat, then tomcat also will allow you to log stuff. Search for Access Valve in the tomcat documentation for the tomcat you are using. That will open up a world of possibilities.
More extensive logging should be the domain of the exception strategy ie the kind of detail you want to see when a problem occurs in the system.