Multiple Render and Action methods in Spring MVC portlet in Liferay - spring

I'm creating a portlet which will take user name in form and display message Welcome in the same portlet after submission of form. For this I've used params in render method.
Note: I'm using spring-MVC with liferay 6.2.
The problem is when I submit name, it redirects to the same page instead of calling another render method.
Here is my view.jsp:
<portlet:actionURL var="actionOneMethodURL">
<portlet:param name="action" value="getUserName">
</portlet:param>
</portlet:actionURL>
<form action="${actionOneMethodURL}" method="post">
Enter Your Name:
<input type="text" name="userName" />
<input type="submit" value="OK!" />
</form>
Here is controller code:
public class PortletController implements Controller {
private static final String WELCOME_PAGE = "welcomeUser";
public void handleActionRequest(ActionRequest request,
ActionResponse response) throws Exception {
}
#ActionMapping(params = "action=getUserName")
public void actionOneMethod(ModelMap model, ActionRequest request,
ActionResponse response) {
String userName = request.getParameter("userName");
model.addAttribute("userName", userName);
response.setRenderParameter("action", "displayName");
}
#RenderMapping
public ModelAndView handleRenderRequest(RenderRequest request,
RenderResponse response) throws Exception {
Map<String, Object> model = new HashMap<String, Object>();
model.put("helloWorldMessage", "Hello There!");
return new ModelAndView("helloWorld", model);
}
#RenderMapping(params = "action=displayName")
public String displayName(ModelMap model, RenderRequest request,
RenderResponse response) throws Exception {
return WELCOME_PAGE;
}
}
Can someone help??
EDIT: Can this happen due to any xml file?? If so which one?

Here is part of code should work:
view.jsp : Name of this form should tell which one of the methods use in controller.
<portlet:actionURL name="actionOneMethod" var="actionOneMethodURL"/>
<form:form action="${actionOneMethodURL}">
<!-- your form body... -->
</form:form>
Controller.java : The one change I did is commented some handler method, and changed your action method to be used by its name. Rest looks fine.
public class PortletController implements Controller {
private static final String WELCOME_PAGE = "welcomeUser";
//I dont think you need this part at all...
/**public void handleActionRequest(ActionRequest request,
ActionResponse response) throws Exception {
}**/
#ActionMapping("actionOneMethod")
public void actionOneMethod(ModelMap model, ActionRequest request,
ActionResponse response) {
String userName = request.getParameter("userName");
model.addAttribute("userName", userName);
response.setRenderParameter("action", "displayName");
}
#RenderMapping
public ModelAndView handleRenderRequest(RenderRequest request,
RenderResponse response) throws Exception {
Map<String, Object> model = new HashMap<String, Object>();
model.put("helloWorldMessage", "Hello There!");
return new ModelAndView("helloWorld", model);
}
#RenderMapping(params = "action=displayName")
public String displayName(ModelMap model, RenderRequest request,
RenderResponse response) throws Exception {
return WELCOME_PAGE;
}
}
I assume you have correct view resolver configured. Here is part of in case:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
I think the part of commented method caused problem. Hope it helps.

I would guess that the problem may be with the param name. In the action try to set a different render parameter.
response.setRenderParameter("page","welcome")
Have a look here simple-spring-portlet

Related

Keep locale on Spring Security session timeout

I'm using Spring Security 3.0.2 and I have this config
<security:form-login
login-processing-url="/resources/j_spring_security_check"
login-page="/login"
authentication-failure-handler-ref="authErrorHandler" authentication-success-handler-ref="authCorrectHandler" />
<security:logout logout-success-url="/index.jsp" invalidate-session="false" />
<security:remember-me />
<security:session-management invalid-session-url="/login/sessionExpired" >
<security:concurrency-control max-sessions="1"
error-if-maximum-exceeded="true" />
</security:session-management>
When I login with a certain locale, all went well but when expiring session, Spring Security clear session and create new anonymous session with locale by default (and go to the login page as expected). The result is the user locale was LOST.
How can I keep the user locale when expiring session in Spring Security 3.0.2?
I'm using localeChangeInterceptor to set the locale, like this:
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="language" />
</bean>
and SessionLocaleResolver as locale resolver:
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="es" />
</bean>
EDIT - SOLVED FOR MY NEEDS
I've solved this finally setting a cookie in my own LocaleChangeInterceptor which extends from HandlerInterceptorAdapter, writing this in preHandle method:
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
if (localeResolver == null) {
throw new IllegalStateException("No LocaleResolver found.");
}
Cookie mylang = new Cookie("mylang", locale.getLanguage() + "_" + locale.getCountry());
mylang.setMaxAge(86400);
response.addCookie(mylang);
localeResolver.setLocale(request, response, locale);
and then in the /sessionExpired controller point, I'm getting the cookie value:
public String sessionExpired(HttpServletRequest request, HttpServletResponse response, Model model,
#CookieValue(value = "mylang", defaultValue = "es_ES") String myLang) throws Exception {
model.addAttribute("mylang", myLang);
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
StringTokenizer st = new StringTokenizer(myLang, "_");
String language = "";
String country = "";
try {
language = (String) st.nextElement();
country = (String) st.nextElement();
} catch (Exception e) {
throw new Exception("Error locale");
}
Locale locale = new Locale(language, country);
localeResolver.setLocale(request, response, locale);
return "sessionExpired";
No need to use database as temporal storage in this case.
Logically it does not look like you can use the session to keep track of the locale. The locale is set using a request param language which will be cleared with the session. When a new session is created the locale is defaulted to es as given by your localeResolver. One way I could think is to store user preferences in a DB and retrieve from there on subsequent log-ins
Also as suggested by #M. Deinum:
If you are ok with cookies use the CookieLocaleResolver which persists the choice in a cookie. Else implement your own LocaleResolver which stores/retrieves from database.
Stumbled upon this old question and just thought of sharing how I got away with my predicament using a Filter (would've preferred an Interceptor but for some reason it annoyingly ain't working for me as of this writing).
public class SessionTimeoutFilter implements Filter {
private String contextPath;
private String language;
#Override
public void init(FilterConfig config) {
contextPath = config.getInitParameter("context.path");
}
#Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String path = request.getRequestURI();
if (path.equals(contextPath)) { //the index page
request.getSession(true);
chain.doFilter(request, response);
} else {
HttpSession session = request.getSession(false);
if (session != null) {
language = (String) session.getAttribute("lang");
chain.doFilter(request, response);
} else {
response.sendRedirect(contextPath + "?timeout=true&lang=" + language);
}
}
}
}
And on top of a LocaleChangeInterceptor, I had parameters in my Controller.
#GetMapping("/")
public String home(#RequestParam(value = "timeout", required = false) Boolean timeout,
#RequestParam(value = "lang", required = false) String language,
HttpServletRequest request, Model model) {
if (Strings.isNotBlank(language)) {
LocaleContextHolder.setLocale(new Locale(language));
} else {
language = LocaleContextHolder.getLocale().getLanguage();
}
if (BooleanUtils.isTrue(timeout)) {
String message = messageService.getMessage("error.timeout", null);
model.addAttribute("message", message);
}
request.getSession().setAttribute("lang", language);
return "index";
}

How To Handle session using Interceptor in Spring 3

I Want to redirect to login whenever the session goes invalid.My servelt.xml is as follows.
<mvc:interceptors>
<bean class="com.package.login.LoginIntercepter" />
</mvc:interceptors>
Interceptor :
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
HashMap details = (HashMap)session.getAttribute("details");
System.out.println("Pre-handle ::"+request.getRequestURI());
if(details!=null){
/*For Checking the Session
* -----Start-----*/
return true;
}else{
response.sendRedirect("Login");//Here Login is action Name which is Mapped in Login Controller
return false;
}
}
Login Controller :
#RequestMapping(value="/Login", method=RequestMethod.GET)
public String loginMethodWithoutaction(HttpServletRequest request,HttpServletResponse response)
{
String page="login";
HttpSession session = request.getSession();
HashMap details = (HashMap)session.getAttribute("details");
if(details!=null)
page = "redirect:/Home";
return page;
}
If Session is invalid then it has to redirect "login" page. otherwise it has to go Home Controller.But its not working.Whenever application get started, the message get printed multiple times and at the end it gives stack overflow.
Message is printing multiple times because when you redirect request is intercepted again and your session is still null because controller method is not executed yet.
You have to create a method that will set details attribute on successful login in your controller.
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession(false);
String path = request.getRequestURI().substring(request.getContextPath().length());
if(path.equals("/Login")){
return true;
}
else if(session == null || session.getAttribute("details") == null) {
request.setAttribute("emassage", "login failed");
throw new LoginFailException("login failed");
}else{
return true;
}
}
LoginFailExceptionClass :
public class LoginFailException extends Exception{
private static final long serialVersionUID = 1L;
public LoginFailException(String message) {
super(message);
}
}
In Controller handle the exception and redirect to login fail page :
#ExceptionHandler(LoginFailException.class)
public String redirectToLogin(){
return "redirect:/login";
}
I think it is your Spring configuration which is not good. Try something like that :
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<ref bean="loginIntercepter"/>
</property>
You have to declare your loginItercepter in the spring file

Stream directly to response output stream in handler method of Spring MVC 3.1 controller

I have a controller method that handles ajax calls and returns JSON. I am using the JSON library from json.org to create the JSON.
I could do the following:
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public String getJson()
{
JSONObject rootJson = new JSONObject();
// Populate JSON
return rootJson.toString();
}
But it is inefficient to put together the JSON string, only to have Spring write it to the response's output stream.
Instead, I can write it directly to the response output stream like this:
#RequestMapping(method = RequestMethod.POST)
public void getJson(HttpServletResponse response)
{
JSONObject rootJson = new JSONObject();
// Populate JSON
rootJson.write(response.getWriter());
}
But it seems like there would be a better way to do this than having to resort to passing the HttpServletResponse into the handler method.
Is there another class or interface that can be returned from the handler method that I can use, along with the #ResponseBody annotation?
You can have the Output Stream or the Writer as an parameter of your controller method.
#RequestMapping(method = RequestMethod.POST)
public void getJson(Writer responseWriter) {
JSONObject rootJson = new JSONObject();
rootJson.write(responseWriter);
}
#see Spring Reference Documentation 3.1 Chapter 16.3.3.1 Supported method argument types
p.s. I feel that using OutputStream or Writer as an parameter is still much more easier to use in tests than a HttpServletResponse - and thanks for paying attention to what I have written ;-)
In the end, I wrote an HttpMessageConverter for this. With it, I can do the following:
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public JSONObject getJson()
throws JSONException
{
JSONObject rootJson = new JSONObject();
// Populate JSON
return rootJson;
}
Here is my HttpMessageConverter class:
package com.example;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
public class JsonObjectHttpMessageConverter
extends AbstractHttpMessageConverter<JSONObject>
{
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
public JsonObjectHttpMessageConverter()
{
super(new MediaType("application", "json"), new MediaType("text", "javascript"));
}
#Override
protected boolean supports(Class<?> clazz)
{
return JSONObject.class.equals(clazz);
}
#Override
protected JSONObject readInternal(Class<? extends JSONObject> clazz,
HttpInputMessage inputMessage)
throws IOException,
HttpMessageNotReadableException
{
throw new UnsupportedOperationException();
}
#Override
protected void writeInternal(JSONObject jsonObject,
HttpOutputMessage outputMessage)
throws IOException,
HttpMessageNotWritableException
{
PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputMessage.getBody(),
getContentTypeCharset(outputMessage)));
try
{
jsonObject.write(writer);
writer.flush();
}
catch (JSONException e)
{
throw new HttpMessageNotWritableException(e.getMessage(), e);
}
}
private Charset getContentTypeCharset(HttpMessage message)
{
MediaType contentType = message.getHeaders().getContentType();
Charset charset = (contentType != null) ? contentType.getCharSet() : null;
return (charset != null) ? charset : DEFAULT_CHARSET;
}
}
The HttpMessageConverter must be registered with Spring. This can be done in the dispatcher-servlet.xml file like this:
<beans ...>
...
<mvc:annotation-driven conversion-service="conversionService" validator="validator">
<mvc:argument-resolvers>
...
</mvc:argument-resolvers>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
<value>*/*</value>
</list>
</property>
<property name="writeAcceptCharset" value="false" />
</bean>
<bean class="com.example.JsonObjectHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
...
</beans>
As you can see, I have other HttpMessageConverter objects registered too. The order does matter.
Note that if you use the OutputStream or Writer it requires you to write the headers yourself.
One workaround is to use InputStreamResource/ResourceHttpMessageConverter

Extending the JSTL View class

I am extending the JSTL view class to implement my own view resolver. But, I am having the problem. Look into my code:
public class TestView extends JstlView {
private String fo_suffix = "_jo";
public void setUrl(String url)
{
//We need to change the inputed url to add a prefix for fo
super.setUrl(url.replace("\\.jsp", fo_suffix+ ".jsp"));
}
public void render(Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
final StringWriter xmlfo = new StringWriter();
HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper(
response) {
#Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(xmlfo);
}
};
super.render(model, request, wrapper);
In the above code, when i am debugging, the control never comes to the setUrl method. So the url is always null in the internal RequestDispatcher.
Please help me to resolve the issue.
Dont forget to put TestView in "myServletName"-servlet.xml
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="test.TestView"/>
....

Spring mvc url parameter

I cannot display may restaurant.
I.ve got my controller class:
#Controller
public class RestaurantController extends MultiActionController{
private RestaurantDAO restaurantDAO;
public void setRestaurantDAO(RestaurantDAO restaurantDAO) {
this.restaurantDAO = restaurantDAO;
}
#RequestMapping("/restaurant/{restaurantId}")
public ModelAndView restaurantid(#PathVariable("contactId") int id,
HttpServletRequest request,
HttpServletResponse response) throws Exception {
Restaurant restaurant = restaurantDAO.findRestaurantById(id);
ModelMap modelMap = new ModelMap();
modelMap.addAttribute("restaurant", restaurant);
return new ModelAndView("restaurant", modelMap);
}
}
im my jsp just:
<c:out value="${restaurant.name }"
in my spring-servlet.xml:
<bean name="/restaurant/**" class="web.RestaurantController" >
<property name="restaurantDAO" ref="myRestaurantDAO"/>
</bean>
Because you mixed up restaurantId and contactId
#RequestMapping("/restaurant/{restaurantId}")
public ModelAndView restaurantid(#PathVariable("contactId") ...
I guess when you change #PathVariable("contactId") to #PathVariable("restaurantId") it will work.
And add #RequestMapping("/restaurant/**") to your controller:
#RequestMapping("/restaurant/**")
#Controller
public class RestaurantController extends MultiActionController{
BTW: What is a MultiActionController?

Resources