i want to ask you about mvc. How it works. So, this is simple example(I don't use any frameworks)
in Controller(Servlet):
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
private void processRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String page = null;
AbstractCommand action;
action = ActionFactory.getAction(request);// get command from factory
page = action.execute(request, response);
RequestDispatcher dispatcher = getServletContext()
.getRequestDispatcher(page);
dispatcher.forward(request, response);
}
for action we create a common interface(Strategy pattern):
public interface AbstractAction {
public String execute(HttpServletRequest request, HttpServletResponse response);
}
Simple Action(Example):
public class HelloAction implements AbstractAction {
#Override
public String execute(HttpServletRequest request,
HttpServletResponse response) {
//....(some actions to modify request)
String page = "/main.jsp";
return page;
}
}
And now, our factory:
public class ActionFactory {
private enum Actions{
HELLO;
}
public static AbstractAction getAction(HttpServletRequest request){
String action = request.getParameter("action");//take parameter from jsp
Actions actionEnum = Actions.valueOf(action.toUpperCase());
switch (actionEnum) {
case HELLO:
return new HelloAction();
}
}
}
We came to the place where I am in confused. Servlet is initialized only once, and only one for all requests. Just forwards requests to the actions where we modify request or response. But, we create NEW instance of the class for every request. Here can occur memory overflow!? Or not?
Can we make these actions static(static method, one for all request)? If two requests come at the same time what will happen to them?
What do you think about this, please share your experience.
P.S. sorry for bad english.
How about Singleton pattern to get the instance of the Action class ?
Just add some abstact getInstance() method in AbstractAction.
Make every implementation provide its own instance.
In every implementation class, use Singleton pattern so that only one instance exists.
Make sure no action class stores any data related to a specific request.
As i understood the jsp, the whole thing is stateless, if u access the servlet by http request, the servlet will be created in a new instance.
After leaving the servlet by .forward(), it will be released by garbage collection.
2,3,...,n requests = 2,3,...,n servlets.
by forwarding to a jsp, the only way to access the servlet from jsp is a new http request = new servlet. ( will move to the doPost method)
Related
in our application we are creating request filters which should not be hit for some urls. We want be able to exclude urls like spring do witch url patterns, e.g.:
// register filter in bean
FilterRegistrationBean filterBeanRegistration = new FilterRegistrationBean();
filterBeanRegistration.setFilter(myFilter());
filterBeanRegistration.addInitParameter("excluded", "*/foo/**, */bar/**");
...
and new filter doesn't hit urls like domain:8080/aaa/foo/xxxx, domain:8080/bbb/bar/xxxx .
Can you tell me how to do that with spring classes or another simple way? Thank you in advice.
EDIT:
There is FilterBeanRegistration#addUrlPatterns(String... urls) method where I can specify urls, but there is no any format which tells which url should hit. For our purposes is better exclude some urls.
You can use org.springframework.web.filter.OncePerRequestFilter. It gets executed once every incoming request. You can override shouldNotFilter method to exclude the URLs you don't want the filter to run for. Example code:
public class MyFilter extends OncePerRequestFilter {
private static final String[] excludedEndpoints = new String[] {"*/foo/**, */bar/**"};
#Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return Arrays.stream(excludedEndpoints)
.anyMatch(e -> new AntPathMatcher().match(e, request.getServletPath()));
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// Filtering logic goes here. call below line on successful authentication.
filterChain.doFilter(request, response);
}
}
I have two action classes
public class TokenAction extends Action {
private ActionForward getToken(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest request,
HttpServletResponse response) throws IOException {
String token = generateToken();
response.setContentType("text/plain");
response.getWriter().print(token);
return null;
}
and
public class ActionTwo extends Action{
private ActionForward doSomething(ActionMapping actionMapping, ActionForm actionForm, HttpServletRequest request,
HttpServletResponse response) {
token = ???
return actionMapping.findForward("page");
}
}
How can I get in ActionTwo from TokenAction?
Basically, in Java there are multiple ways to pass objects across contexts, the most popular being likely:
through static variables (not recommended)
through shared parameter maps
through a controller object
In your case, since the parameters passed to the methods seem to have a lifetime that encompasses both calls (although it's hard to say without the specifics), you should probably store them in the parameters (HttpServletResponse isn't very useful for that purpose, but the ActionMapping and ActionForm likely are). If your Actions are created in the context of some controller, you could use the controller to pass the parameter instead.
I have a question with Spring MVC RequestMapping annotation. need your help.
I have created one IPSLcontroller and i want that IPSLcontroller to handle all request url.i have created two method in this controller.
1)handleLogoutRequest :- this method should invoke on below url.
2)handleRequest :- this method should invoke on all request url otherthan logout.
http://localhost:9086/webapp/login
or
http://localhost:9086/webapp/add
or
http://localhost:9086/webapp/remove
here is my sample code. but it's not working as expected.
#Controller
public class IPSLController {
#RequestMapping(value={"/logout/*"},method = RequestMethod.POST)
protected void handleLogoutRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out
.println("........................IPSLController logout request.......................................");
}
#RequestMapping(method = RequestMethod.POST,value={"/*"})
protected void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out
.println("........................IPSLController all request Post.......................................");
}
}
You should use a general Prefix for every controller you use, so you can differ between them better. Also you donĀ“t need any "/" for calls like this.
#Controller
#RequestMapping("ispl")
public class IPSLController {
#RequestMapping(value={"logout"},method = RequestMethod.POST)
protected void handleLogoutRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out
.println("........................IPSLController logout request.......................................");
}
#RequestMapping(method = RequestMethod.POST,value={"hello"})
protected void handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out
.println("........................IPSLController all request Post.......................................");
}
}
If you now want to call them over a ServletRequest or with a restService or something similar you should declare them like this
#GET
#Path("ispl/logout")
public void Method (HttpServletResponse ...)
Well it is working the way it should. You have a mapping for /* and for /logout/*. So when you post to /logout it invokes the method for /*. I suspect that if you post to /logout/something it would invoke your logout handler.
If you want it to work, you cannot have a wildcard mapping for the second method. At least use /something/* so that spring can make a correct decision on mappings.
I have created a portlet and able all my business logic is performing in a servlet. I need to get the liferay login user details in the servlet. SO I have created a class which will extend the GenericPortlet. Now My question is how can I call that class I need to execute the GenericPorlet unimplemented method. My code is as follows,
public class ActionProcess extends GenericPortlet {
public void init() throws PortletException{
super.init();
}
public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
User user = (User) request.getAttribute(WebKeys.USER);
ThemeDisplay td =(ThemeDisplay)request.getAttribute(WebKeys.THEME_DISPLAY);
User urs = td.getUser();
System.out.println("doView "+ urs);
System.out.println("doView "+ user);
}
}
Now I need to call the doView() and return the values to servlet. How can I do that my servlet code is.
#WebServlet("/demoClass")
public class demoClass extends HttpServlet {
private static final long serialVersionUID = 1L;
public demoClass() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(request, response); //
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//Here I am performing the business logic....
//How do I call the ActionProcess class here, I need to get the User name which is return by diView() method
}
}
Any suggestions?
You can't, and my answer is very similar to my answer to your very similar question.
It's the framework's (portal's) business to call the lifecycle methods of a portlet. Not yours.
You need to rethink your problem and come up with a different architecture. Or give us your problem to suggest a different solution than the one that you're currently pursuing.
Differing from that answer, I'm assuming that in this case you're within the very same same web application (portlet and servlet are deployed in the same webapp). However, just like in that other question, a portlet's request is routed through the portal while the servlet's request is not. You'll not have the data available.
//MyServlet.java
public class MyServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, Exception {
int sum = Integer.parseInt(request.getParameter("a")) + Integer.parseInt(request.getParameter("b"));
request.setAttribute("sum",sum);
RequestDispatcher dispatcher=request.getRequestDispatcher("/ShowSum.jsp");
dispatcher.forward(request,response);
}
}
//TestServelt.java
public class TestServelt {
#Test
public void testSum() throws Exception {
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
RequestDispatcher dispatcher = mock(RequestDispatcher.class);
when(request.getParameter(a)).thenReturn(10);
when(request.getParameter(b).thenReturn(20);
when(request.getRequestDispatcher(anyString())).thenReturn(dispatcher);
MyServlet testServlet = new MyServlet ();
testServlet.doPost(request, response);
int sum = (int)request.getAttribute("sum"); // here it's will return NULL.
}
}
I am trying to write somewhat similar Test case for a servlet
as u can see , that sum variable can't be mocked cuz that will defeat the purpose , i want it to return what got calculated after the servlet call. can anyone help or give a different approach.
You can't use mock objects in this case; mock objects are just thin API layers, they have no functionality or intelligence.
Use a framework with simulates the Servlet API like mockrunner or the Spring Web testing framework.