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..
Related
This question already has answers here:
Servlet and path parameters like /xyz/{value}/test, how to map in web.xml?
(7 answers)
Closed 1 year ago.
I'm learning servlets and I want to create two different endpoints in a single servlet.
I mean, I want to have /hello and /test each one of them should execute or refer to different class as shown below.
In other words, I want to be able to acceess to:
http://localhost:8080/HelloServlet/hello
and
http://localhost:8080/HelloServlet/Test
So that the corresponding or the respective class must be invoked and display the respective contents
HelloWorld example:
#WebServlet(name = "HelloServlet", urlPatterns = {"/sayHello", "/hello", "/helloWorld"})
public class HelloWorld extends HttpServlet{
private String responseContentType = null;
public HelloWorld() {
super();
}
public void init() throws ServletException {
responseContentType = "text/html;charset=UTF-8";
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// Set the response message's MIME type
response.setContentType(responseContentType);
// Allocate a output writer to write the response message into the network socket
PrintWriter out = response.getWriter();
// Write the response message, in an HTML page
try {
out.println("<!DOCTYPE html>");
out.println("<html><head>");
out.println("<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>");
out.println("<title>Hello, World</title></head>");
out.println("<body>");
out.println("<h1>Hello, world!</h1>"); // says Hello
// Echo client's request information
out.println("<p>Request URI: " + request.getRequestURI() + "</p>");
out.println("<p>Protocol: " + request.getProtocol() + "</p>");
out.println("<p>PathInfo: " + request.getPathInfo() + "</p>");
out.println("<p>Remote Address: " + request.getRemoteAddr() + "</p>");
// Generate a random number upon each request
out.println("<p>A Random Number: <strong>" + Math.random() + "</strong></p>");
out.println("</body>");
out.println("</html>");
} finally {
out.close(); // Always close the output writer
}
}
}
Test example:
#WebServlet(name = "HelloServlet", urlPatterns = {"/test"})
public class Test extends HttpServlet{
private String responseContentType = null;
public Test() {
super();
}
public void init() throws ServletException {
responseContentType = "text/html;charset=UTF-8";
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
// Set the response message's MIME type
response.setContentType(responseContentType);
// Allocate a output writer to write the response message into the network socket
PrintWriter out = response.getWriter();
// Write the response message, in an HTML page
try {
out.println("<!DOCTYPE html>");
out.println("<html><head>");
out.println("<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>");
out.println("<title>Hello, World</title></head>");
out.println("<body>");
out.println("<h1>TEST</h1>"); // says Hello
// Echo client's request information
// Generate a random number upon each request
out.println("<p>A Random Number: <strong>" + Math.random() + "</strong></p>");
out.println("</body>");
out.println("</html>");
} finally {
out.close(); // Always close the output writer
}
}
}
web.xml:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
<display-name>HelloServlet</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.examples.HelloWorld</servlet-class>
<servlet-class>com.examples.Test</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/sayHello</url-pattern>
<url-pattern>/hello</url-pattern>
<url-pattern>/helloWorld</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
</webapp>
If you really want to create two DIFFERENT endpoints inside the same class, for whatever strange reason, here's 2 solutions I can think of:
Try implementing an inner class with the #WebServlet annotation. I don't know if that gets picked up and installed, but worth a try
Have two classes, but let the second class (with the second address) call into the first class. This is what I often do (static) when I have a task that is needed by multiple pages.
I myself once wrote a library that resolved Annotations to addresses, and I thought "ahh I'm better than that stupid JEE stuff... I will allow single methods to be anotated too". Which was not difficult to implement at all.
BUT: I regret doing that, because the software that used that got really clumsy and strange, with one file being the possible root of multiple endpoints...
So when I re-designed that library, I removed that function and now only allow endpoint annotations on class level. Projects sticking to this are just SO MUCH cleaner and easier to maintain.
Well... so those two options are out there for JEE.
But the most important questio is: WHY would you want what you are asking for?
This seems like an XY question: https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem.
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.
When I am trying to retrieve data from database it's showing NullPointerException.
Here is my servlet code:
public class displayData extends HttpServlet {
String query;
Connection conn;
Statement st;
ResultSet res;
ConnectionManager dbconn;
List lst= new ArrayList();
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try
{
dbconn= new ConnectionManager();
conn=dbconn.getConnection();
st=conn.createStatement();
query="select * from reg";
res=dbconn.getResultSet(query, conn);
System.out.println(res);
while(res.next())
{
lst.add(res.getString("uname"));
lst.add(res.getString("password"));
}
res.close();
}catch(Exception e)
{
RequestDispatcher rd= request.getRequestDispatcher("/error.jsp");
rd.forward(request, response);
}
finally
{
request.setAttribute("EmpData", lst);
response.sendRedirect("/success.jsp");
RequestDispatcher rd= request.getRequestDispatcher("/success.jsp");
rd.forward(request, response);
lst.clear();
out.close();
}
}
And Here is JSP Code for Retrieving Data from database using above servlet Code:
<body>
<h1>Employee List</h1>
<% Iterator itr;%>
<% List data = (List) request.getAttribute("EmpData");
for(itr=data.iterator(); itr.hasNext();)
{
%>
<tr>
<% String s= (String) itr.next();%>
<td><%=s%></td>
<td><%=itr.next()%></td>
<td><input type="submit" value="Edit" onclick="editRecord(<%=s%>;)"</td>
<td><input type="submit" value="Delete" onclick="deleteRecord(<%=s%>;)"</td>
<%}%>
</tr>
</body>
Please help me for solving this problem.
After seeing your Servlet code I found multiple issues,Lets go one by one
I am not sure whether you defined your servlet as a servlet or not.
Either do mapping in web.xml or add annotation like this
#WebServlet("/displayData") public class displayData extends
HttpServlet {
In the servlet you don't have doGet and doPost method. So your
method processRequest will not be invoked by the container. either
put doGet and call your service method or rename your service method
to doGet. Reference - Is it mandatory to have a doGet or doPost method?
The disaster you done in try catch finally block. finally will be always called so there is no use writing the redirection code there as it will executed after catch also. In addition to that finally blocks first four lines are causing serious issues. You should not call both sendRedirect and forward one followed by another. Either do sendRedirect or do forward but not both at the same time.
You will get this exception illegalstateexception-cannot-forward-after-response-has-been-committed Reference - java.lang.IllegalStateException: Cannot forward after response has been committed
What to do forward or sendRedirect at last, In this case you have to
use forward as its a server side action. Reference -
Request Attributes not available in jsp page when using sendRedirect from a servlet
Based on your path of jsp do forward. if your success and error
jsp's are directly under Webcontent then do like this
request.getRequestDispatcher("success.jsp");
Change these things and try again if not working let me know
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.
[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>