[working with JEE, MVC, servlets, JSP]
In web.xml i have specified home.jsp page as application entry point:
<welcome-file-list>
<welcome-file>/home.jsp</welcome-file>
</welcome-file-list>
In my application I have next servlet:
#WebServlet("/show")
public class ShowPostsController extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
private PostDAOLocal postDao;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
List<Post> posts = null;
String sort = request.getParameter("sort");
// current page number
int page = Integer.parseInt(request.getParameter("page"));
// the number of entries to show on a "page"
int postsPerPage = Integer.parseInt(request.getParameter("postsPerPage"));
if(sort.equals("byVisitors"))
posts = postDao.getMostVisitedPosts();
else if(sort.equals("byComments"))
posts = postDao.getMostCommentedPosts();
else
posts = postDao.getNewestPosts(page, postsPerPage);
request.setAttribute("posts", posts);
RequestDispatcher dispatcher = request.getRequestDispatcher("home.jsp");
dispatcher.forward(request, response);
}
Now, how can I make make this servlet to be invoked before home.jsp page is loaded, on application start? (because I would like to display some data on home.jsp that are being extracted from database, and set as request attributes inside servlet's doGet method)
Now, how can I make make this servlet to be invoked before home.jsp page is loaded, on application start?
If by "on application start" you mean "when the application is accessed for the first time by a user using the default path" and all you want is the servlet to be called by default instead of the jsp, then try replacing /home.jsp by /show in your welcome-file-list, e.g.:
<welcome-file-list>
<welcome-file>/show</welcome-file>
</welcome-file-list>
If it doesn't work, try without the leading slash before show.
Edit: Regarding the other question in the comments. To use default values, you can check if getParameter() returns null and if it does, assign a default value to the local variable, e.g.:
String sort = request.getParameter("sort");
if (sort == null) {
sort = "someDefaultValue";
}
Do load a servlet on application start you need to edit the web.xml
<servlet>
<servlet-name>******</servlet-name>
<display-name>******</display-name>
<servlet-class>******</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Related
I have a login servlet and after successful login, I want the user to
/login/{username}/
How can I place username in the URL for POST request?
I have looked up certain answers like this and this but couldn't understand how to actually accomplish my goal.
I would like to stick to using servlets and refrain from using technologies like JAX-RS and so on.
This is my login logic implementation:
private void login_doIT(HttpServletRequest request, HttpServletResponse response) throws SQLException, InvalidKeySpecException, NoSuchAlgorithmException, ServletException, IOException {
String userInput = request.getParameter("user_name");
String pass = request.getParameter("pass");
pst = c.prepareStatement(query);
pst.setString(1,userInput);
rs = pst.executeQuery();
while (rs.next()){
imiya = rs.getString("user_name");
kyuch = rs.getString("key");
kodom = rs.getBytes("nitrate");
}
EncryptClass instance = new EncryptClass(2048,100000);
if(instance.chkPass(pass,kyuch,kodom) && imiya.equals(userInput)){
HttpSession session = request.getSession();
session.setAttribute("userLogged",userInput);
request.setAttribute("title",userInput);
String pathInfo = request.getPathInfo();
if(pathInfo!=null || !pathInfo.isEmpty()){
String[] pathArr = pathInfo.split("/");
String val = pathArr[1];//{username}
//now what??.....
}
request.getRequestDispatcher("/LoginLanding.jsp").forward(request,response);
} else {
request.setAttribute("message", message);
request.getRequestDispatcher("/index.jsp").include(request,response);
}
}
And this is the web.xml for it:
<servlet>
<servlet-name>Login</servlet-name>
<servlet-class>AuthPack.ServletLogin</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Login</servlet-name>
<url-pattern>/Login/*</url-pattern>
</servlet-mapping>
After I submit the form, the URL becomes something like
/login
But I want it like this:
/login/{username}
more preferably:
/{username}
you have to use a url rewriter or a filter.
Here is an example using a filter method:
in your login servlet instead of going to loginLanding.jsp
you redirect to the filter like so:
//REDIRECT TO filter
response.sendRedirect("/user/"+userInput);
To create a filter, it's very similar to creating a servlet, and you get the option to create a mapping like this (web.xml):
<filter>
<display-name>UserFilter</display-name>
<filter-name>UserFilter</filter-name>
<filter-class>filters.UserFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UserFilter</filter-name>
<url-pattern>/user/*</url-pattern>
</filter-mapping>
Your filter should look something like this:
public class UserFilter implements Filter {
public UserFilter() {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String requri = ((HttpServletRequest) request).getRequestURI().substring(((HttpServletRequest) request).getContextPath().length() + 1);
HttpSession session = (((HttpServletRequest) request).getSession());
String RequestedUsername = null;
if(requri.contains("user/")){
//get the username after "user/"
RequestedUsername=requri.substring(5);
if(!RequestedUsername.isEmpty()){
//if not empty set session
session.setAttribute("loggedInUser",RequestedUsername);
}
}
//forward to servlet which will set user details etc... (just get the user session variable from there) in that servlet you forward to landinglogin.jsp
request.getRequestDispatcher("/profile").forward(request, response);
}
In this code, you expect the parameters to be in the available in HttpServletRequest.getParameter() accessed from the doPost() method in your servlet:
String userInput = request.getParameter("user_name");
String pass = request.getParameter("pass");
But you don't show whether you are a) submitting the request as a POST or b) accessing these from the doPost() call in your servlet.
You can access parameter information on the path by using HttpServletRequest.getPathInfo() (see this link)
String extraPathInfo = request.getPathInfo();
// If extraPathInfo is not null, parse it to extract the user name
String pass = request.getParameter("pass");
If your servlet is available at /login and you append the user name to that (like /login/someUser/) then getPathInfo() will return that, though you may want to check whether this includes the slashes.
As an aside, doing this for a login feature creates a security vulnerability. Rather than putting user names on the path, it's better to simply send both the username and password as POST parameters.
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.
I am trying to pass the value from one servlet to another, and I think I have tried just about everything but it always ends up null.
I am trying to get the "id" from beside delete task. I have tried storing it in a session, I have tried playing with request.getParameter. Any ideas on what I should do?
try{
int id = DataAccess.getUserID(name);
list = DataAccess.displayTasks(id);
}
catch(Exception e){e.printStackTrace();}
out.println(OurUtils.getHeader("List of Tasks"));
out.println("<center><h2>List of Your Tasks</h2>");
out.println("<table>");
for (Tasks T : list){
out.println("<tr>");
out.println("<td>Delete</td>");
out.println("<td>Modify</td>");
out.println("<td>"+T.getTask()+"</td></tr>");
}
out.println("</table>");
out.println("");
out.println("Add a new task");
out.println("</center>");
out.println(OurUtils.getFooter());
here is my display task method
public static ArrayList<Tasks> displayTasks(int id) throws ClassNotFoundException,
IllegalAccessException, InstantiationException,SQLException{
Class.forName(driver).newInstance();
con = DriverManager.getConnection(url,sqluser,sqlpass);
st = con.createStatement();
String sql = "SELECT task from Assignment2Tasks where userID = "+id+"";
ResultSet rs = st.executeQuery(sql);
ArrayList<Tasks> list = new ArrayList<Tasks>();
while(rs.next()){
Tasks T = new Tasks(rs.getString(1));
list.add(T);
}
con.close();
return list;
Okay, maybe you already know it, but this is how your service objects (such as DAO objects) and domain objects (lists of tasks) can be shared across your servlets:
In your web.xml you define listener object, implementing ServletContextListener, so listener will be called once application is deployed into Servlet container (jetty, tomcat):
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>Main</servlet-name>
<servlet-class>vic.web.MainServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<listener>
<listener-class>vic.web.AppInitializationListener</listener-class>
</listener>
<servlet-mapping>
<servlet-name>Main</servlet-name>
<url-pattern>/main</url-pattern>
</servlet-mapping>
</web-app>
In code of that listener you initialize your data layer and put reference to it inside ServletContext, which is guaranteed to be shared across all servlets of your webapp, which are run in the same JVM:
public class AppInitializationListener implements ServletContextListener {
private static final Logger logger = LoggerFactory.getLogger(MainServlet.class);
static final String INITIAL_TASKS_KEY = "INITIAL_TASKS_KEY";
#Override
public void contextInitialized(ServletContextEvent sce) {
logger.info("Application initialization commences...");
sce.getServletContext().setAttribute(INITIAL_TASKS_KEY,
new TasksList(Arrays.asList("From me to you", "We can work it out", "Long and winding road")
));
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
In code of your servlet(s), you override init(ServletConfig config) method which is called by container once servlet is initialized. There, you reach out for data initialized in listener and here you go!
public class MainServlet extends HttpServlet {
private static final Logger logger = LoggerFactory.getLogger(MainServlet.class);
private TasksList initialTasks;
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
logger.info("Here");
ServletContext ctx = getServletContext();
//noinspection unchecked
initialTasks = (TasksList) ctx.getAttribute(AppInitializationListener.INITIAL_TASKS_KEY);
logger.info("Got: " + initialTasks);
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
StringBuilder sb = new StringBuilder("<html><body>Hello there. Here are your tasks:<br><ol><br>\n");
for (String task : initialTasks.getTasks()) {
sb.append("<li>").append(task).append("</li><br>\n");
}
sb.append("</ol>\n</body></html>");
writer.write(sb.toString());
writer.flush();
writer.close();
}
}
Here data layer is just POJO containing static list of tasks. Since you want to get data from DB (naturally), you should put your JDBC initialization code in listener as shown above and make listener put obtained DriverManager into context.
Okay, but in reality you will want to change these things: a) use some MVC framework instead of creating HTML by hand; b) Use DataSource and pool of JDBC connections instead of DriverManager
I dont know why you're using all those out.println instead of atleast jsp. I've done this in jsp.
My list in servlet
List<User> list = userService.viewUser(); //userService is used to access the data from db by calling the daoservice
request.setAttribute("list",list);
rs=request.getRequestDispatcher("manageuser.jsp");
rs.include(request,response);
This is my code in jsp, do note that all these data are inside table tag
<%List list=(List)request.getAttribute("list");%> //Getting the list attributes from the appropriate servlet
<c:forEach items="${list}" var="user"> //for each loop
<tr>
<td><c:out value="${user.userId}" /></td>
<td><c:out value="${user.userName}" /></td>
<td><c:out value="${user.emailId}" /></td>
<td>Edit
Delete</td>
</tr>
</c:forEach>
Then in the servlet where I was doing the deleting operation and editind operation, (for you it's only deletion)
int id = Integer.parseInt(request.getParameter("Id")); //Do the appropriate actions from this id variable
Inter-servlet communication:
RequestDispatcher object can forward a client's request to a resource(Servelt/Jsp).Here you want Servlet_A to invoke Servlet_B.Use
RequestDispatcher dispatcher = getRequestDispatcher("Servlet_B");
dispatcher.forward( request, response );
<a href = \DeleteTask?id = 15>Delete</a>
when user clicks Delete, you can get id by request.getParameter("id")
So you can pass id to other servlet with request.
Also you can store it in session and get it.
request.getSession(true).setAttribute("name",'AAAA');
request.getSession().getAttribute("name");
I have discovered the solution to my problem. In my DisplayTasks method, I was just pulling the string for the task and putting it in the t object and I was not pulling the ID from the table. I couldn't pass the ID to the other servlet because it was and empty variable..
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
If I've something like this:
<servlet>
<display-name>Step</display-name>
<servlet-name>Step</servlet-name>
<servlet-class>com.foo.AServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Step</servlet-name>
<url-pattern>/aservlet/*</url-pattern>
</servlet-mapping>
and the servlet is invoked by a request of the form /aservlet/ABC
then is there a way to get the value "ABC" in the code? i.e inside the doGet() or doPost() methods of the class AServlet?
THe easiest thing to do is,
String path = request.getPathInfo();
Which returns "/ABC".
public void doGet(HttpServletRequest request, HttpServletResponse response){
String uriRequest = request.getRequestURI();
//parse to obtain only the last part
String uriRequest = uriRequest.substring(uriRequest.lastIndexOf("/")+1);
}
Same thing for doPost().