Sunday 6 September 2015

Spring Annotation Based Controllers


@Controller Annotation

For the @Controller annotation spring gives a feature of autodetection. Adding “component-scan” in spring-context and provide the base-package.

       <!-- Controller package -->
       <context:component-scan base-package="com.abusecore.controller" />
       <mvc:annotation-driven />

The dispatcher will start from the base-package and scan for beans that are annotated with @Controller annotation and look for @RequestMapping.

@Controller annotation just tells the container that this bean is a designated controller class.



@RequestMapping Annotation

@RequestMapping annotation is used to map a particular HTTP request method (GET/POST) to a specific class/method in controller which will handle the respective request.

@RequestMapping annotation can be applied both at class and method level. In class level we can map the URL of the request and in method we can map the URL as well as HTTP request method (GET/POST).

We can use wildcard characters like * for path pattern matching.

In the following example, @RequestMapping(“/AbuseCore-1”) annotated at class level maps the request URLand at again at lower level method level mapping is used for HTTP request mapping.

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.abusecore.model.Count;
import com.abusecore.model.Status;
import com.abusecore.model.Ticket;
import com.abusecore.services.IDataServices;

@Controller
@RequestMapping("/AbuseCore-1")
public class RestController {

       @Autowired
       IDataServices dataServices;

       /** Logger class to display logs. */
       static final Logger logger = Logger.getLogger(RestController.class);


       @RequestMapping(value = "/count-tickets.json", method = RequestMethod.GET)
       public @ResponseBody Count getTicketsCount() {
              Count count = dataServices.getTicketsCount();
              logger.info("total tickets :" + count);
              return count;
       }

       @RequestMapping(value = "/create", method = RequestMethod.POST,
                     consumes = MediaType.APPLICATION_JSON_VALUE)
       public @ResponseBody Status addEmployee(@RequestBody Ticket ticket) {
              try {
                     dataServices.addEntity(ticket);
                     return new Status(1, "Ticket added Successfully !");
              } catch (Exception e) {
                     // e.printStackTrace();
                     return new Status(0, e.toString());
              }
       }
}

Multi-action Controller

In a multi-action controller URLs are mapped at method level since the controller services multiple URLs.

In given code, two URLs are serviced by the controller and they are mapped to separate methods.

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class HelloWorldController {

       @RequestMapping("/")
       public String hello() {
              return "hello";
       }

       @RequestMapping(value = "/hi", method = RequestMethod.GET)
       public String hi(@RequestParam("name") String name, Model model) {
              String message = "Hi " + name + "!";
              model.addAttribute("message", message);
              return "hi";
       }
}


When we use multi-action form controller there is a possibility of creating ambiguity in mapping the URLs to methods.

In that case, org.springframework.web.servlet.mvc.multiaction.MethodNameResolver helps us to resolve the ambiguity method mapping.

If MethodNameResolver is not specified then by default org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver is used.

This default implementation does not support wildcard characters.

When a matching method is not found, action will be mapped to a default method in the controller which does not have any @RequestMapping specified.

If there are more such methods in the controller, then method name will be taken into consideration.

<beans>
       <bean class="org.springframework.web.servlet.mvc.support.
                   ControllerClassNameHandlerMapping"/>
       <bean class="com.spring.mvc.controller.HelloWorldController">
              <property name="methodNameResolver">
                     <bean class="org.springframework.web.servlet.mvc.multiaction.
                                PropertiesMethodNameResolver">
                           <property name="mappings">
                                  <props>
                                         <prop key="/">hello</prop>
                                         <prop key="/hi">hi</prop>
                                  </props>
                           </property>
                     </bean>
              </property>
       </bean>
</beans>



@RequestParam Annotation

org.springframework.web.bind.annotation.RequestParam

Annotation which indicates that a method parameter should be bound to a web request parameter.

Supported for annotated handler methods in Servlet and Portlet environments.

If the method parameter type is Map and a request parameter name is specified, then the request parameter value is converted to a Map assuming an appropriate conversion strategy is available.

If the method parameter is Map<String, String> or MultiValueMap<String, String> and a parameter name is not specified, then the map parameter is populated with all request parameter names and values.

@RequestMapping(value = "/ticket.json", method = RequestMethod.GET)
public @ResponseBody Ticket getTicket 
     (@RequestParam(value="ticket_id",required=false,defaultValue="0")int ticketId) {
       Ticket ticket = null;
       ticket = dataServices.getEntityById(ticketId);
       if(ticket!=null) {
              logger.info("ticket #" +ticketId+ "load successfully");
       }
       return ticket;
}



@SessionAttributes

@SessionAttributes annotation is used on the class level to:

1.    Mark a model attribute should be persisted to HttpSession after handler methods are executed

2.    Populate your model with previously saved object from HttpSession before handler methods are executed -- if one do exists.

So you can use it alongside your @ModelAttribute annotation like in this example:

@Controller
@RequestMapping("/counter")
@SessionAttributes("mycounter")
public class CounterController {

  // Checks if there's a model attribute 'mycounter', if not create a new one.
  // Since 'mycounter' is labelled as session attribute it will be persisted to
  // HttpSession
  @RequestMapping(method = GET)
  public String get(Model model) {
    if(!model.containsAttribute("mycounter")) {
      model.addAttribute("mycounter", new MyCounter(0));
    }
    return "counter";
  }

  // Obtain 'mycounter' object for this user's session and increment it
  @RequestMapping(method = POST)
  public String post(@ModelAttribute("mycounter") MyCounter myCounter) {
    myCounter.increment();
    return "redirect:/counter";
  }
}
 Make sure you make your session objects Serializable.

@CookieValue

@CookieValue annotation is used to bind a method parameter to a HTTP cookie. In below example, a cookie with key “username” value will be bound to method variable name.

@RequestMapping("/hi")
public void userInfo(@CookieValue("username") String name)  {
       // code
}

@RequestHeader

@RequestMapping("/hi")
public void hostInfo(@RequestHeader("Host") String host)  {

       //...
}

Very similar to cookie binding, @RequestHeader is used to bind a header value to a method parameter.

Assume we have the following header value, and the following annotation in controller will bind the host variable to the value.

Host: localhost: 8080


No comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...