Implementing Controllers - Java-Springs

Controllers provide access to the application behavior that you typically define through a service interface.Controllers interpret user input and transform it into a model that is represented to the user by the view.Spring implements a controller in a very abstract way, which enables you to create a wide variety of controllers.

Spring 2.5 introduced an annotation-based programming model for MVC controllers that uses annotations such as @Request Mapping, @Request Param, @Model Attribute, and so on. This annotation support is available for both Servlet MVC and Portlet MVC.Controllers implemented in this style do not have to extend specific base classes or implement specific interfaces. Furthermore, they do not usually have direct dependencies on Servlet or Portlet APIs, although you can easily configure access to Servlet or Portlet facilities.

@Controller
public class HelloWorldController {
@RequestMapping("/helloWorld")
public ModelAndView helloWorld() {
ModelAndView mav = new ModelAndView();
mav.setViewName("helloWorld");
mav.addObject("message", "Hello World!");
return mav;
}
}

As you can see, the @Controller and @Request Mapping annotations allow flexible method names and signatures. In this particular example the method has no parameters and returns a Model And View, but various other (and better) strategies exist. Model And View, @Controller, and @RequestMapping form the basis for the Spring MVC implementation. This documents these annotations and how they are most commonly used in a Servlet environment.

Defining a controller with @Controller

The @Controller annotation indicates that a particular class serves the role of a controller.Spring does not require you to extend any controller base class or reference the Servlet API. However, you can still reference Servlet-specific features if you need to.

The @Controller annotation acts as a stereotype for the annotated class, indicating its role.The dispatcher scans such annotated classes for mapped methods and detects @Request Mapping annotations.

You can define annotated controller beans explicitly, using a standard Spring bean definition in the dispatcher's context. However, the @Controller stereotype also allows for autodetection, aligned with Spring general support for detecting component classes in the classpath and auto-registering bean definitions for them.

Mapping requests with @RequestMapping

You use the @Request Mapping annotation to map URLs such as /appointments onto an entire class or a particular handler method.Typically the class-level annotation maps a specific request path (or path pattern) onto a form controller, with additional method-level annotations narrowing the primary mapping for a specific HTTP method request method ("GET"/"POST") or specific HTTP request parameters.

The following example shows a controller in a Spring MVC application that uses this annotation:

@Controller
@RequestMapping("/appointments")
public class AppointmentsController {
private final AppointmentBook appointmentBook;
@Autowired
public AppointmentsController(AppointmentBook appointmentBook) {
this.appointmentBook = appointmentBook;
}
@RequestMapping(method = RequestMethod.GET)
public Map<String, Appointment> get() {
return appointmentBook.getAppointmentsForToday();
}
@RequestMapping(value="/{day}", method = RequestMethod.GET)
public Map<String, Appointment> getForDay(@PathVariable.
@DateTimeFormat(iso=ISO.DATE) Date day, Model model) return
appointmentBook.getAppointmentsForDay(day);
}
@RequestMapping(value="/new", method = RequestMethod.GET)
public AppointmentForm getNewForm() {
return new AppointmentForm();
}
@RequestMapping(method = RequestMethod.POST)
public String add(@Valid AppointmentForm appointment, BindingResult result) {
if (result.hasErrors()) {
return "appointments/new";
}
appointmentBook.addAppointment(appointment);
return "redirect:/appointments";
}
}

In the example, the @Request Mapping is used in a number of places.The first usage is on the type (class) level, which indicates that all handling methods on this controller are relative to the /appointments path. The get() method has a further @Request Mapping refinement: it only accepts GET requests, meaning that an HTTP GET for /appointments invokes this method. The post() has a similar refinement, and the get New Form() combines the definition of HTTP method and path into one, so that GET requests for appointments/new are handled by that method.

The get For Day() method shows another usage of @Request Mapping: URI templates.

A @Request Mapping on the class level is not required. Without it, all paths are simply absolute, and not relative.The following example from the Pet Clinic sample application shows a multi-action controller using @Request Mapping:

@Controller
public class ClinicController {
private final Clinic clinic;
@Autowired
public ClinicController(Clinic clinic) {
this.clinic = clinic;
}
@RequestMapping("/")
public void welcomeHandler() {
}
@RequestMapping("/vets")
public ModelMap vetsHandler() {
return new ModelMap(this.clinic.getVets());
}
}

URI Templates

To access parts of a request URL in your handling methods, use the URI templates in the @Request Mapping path value.

Use the @Path Variable method parameter annotation to indicate that a method parameter should be bound to the value of a URI template variable.

The following code snippet shows the usage of a single @Path Variable in a controller method:

@Request Mapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable String ownerId, Model model) {
Owner owner = ownerService.findOwner(ownerId);
model.addAttribute("owner", owner);
return "displayOwner";
}

The URI Template "/owners/{ownerId}" specifies the variable name ownerId. When the controller handles this request, the value of ownerId is set to the value in the request URI. For example,when a request comes in for /owners/fred, the value fred is bound to the method parameter String ownerId. The matching of method parameter names to URI Template variable names can only be done if your code is compiled with debugging enabled. If you do not have debugging enabled, you must specify the name of the URI Template variable name in the @PathVariable annotation in order to bind the resolved value of the variable name to a method parameter. For example:

@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable("ownerId") String ownerId, Model model) {
// implementation omitted
}

You can also use a controller method with the following signature:

@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {
// implementation omitted
}

You can use multiple @Path Variable annotations to bind to multiple URI Template variables:

@RequestMapping(value="/owners/{ownerId}/pets/{petId}", method=RequestMethod.GET)
public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
Owner owner = ownerService.findOwner(ownderId);
Pet pet = owner.getPet(petId);
model.addAttribute("pet", pet);
return "displayPet";
}

The following code snippet shows the usage of path variables on a relative path, so that the findPet()method will be invoked for /owners/42/pets/21, for instance.

@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@RequestMapping("/pets/{petId}")
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}

Advanced @RequestMapping options

In addition to URI templates, the @Request Mapping annotation also supports Ant-style path patterns (for example, /myPath/*.do). A combination of URI templates and Ant-style globs is also supported (for example, /owners/*/pets/{petId}).

The handler method names are taken into account for narrowing if no path was specified explicitly, according to the specified org. pring frame work web. servlet. mvc. multiaction. Method Name Resolver (by default an org. spring frame work. web. servlet. mvc. multiaction. Internal Path Method Name Resolver).

This only applies if annotation mappings do not specify a path mapping explicitly. In other words, the method name is only used for narrowing among a set of matching methods; it does not constitute a primary path mapping itself.

If you have a single default method (without explicit path mapping), then all requests without a more specific mapped method found are dispatched to it. If you have multiple such default methods, then the method name is taken into account for choosing between them.

You can narrow path mappings through parameter conditions: a sequence of "myParam= myValue" style expressions, with a request only mapped if each such parameter is found to have the given value. For example:

@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@RequestMapping(value = "/pets/{petId}", params="myParam=myValue")
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}

"myParam" style expressions are also supported, with such parameters having to be present in the request (allowed to have any value). Finally, "!myParam" style expressions indicate that the specified parameter is not supposed to be present in the request.

Similarly, path mappings can be narrowed down through header conditions:

@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@RequestMapping(value = "/pets", method = RequestMethod.POST, headers="content-type=text/*")
public void addPet(Pet pet, @PathVariable String ownerId) {
// implementation omitted
}
}

In the above example, the addPet() method is only invoked when the content-type matches the text/* pattern, for example, text/xml.

Supported handler method arguments and return types

Handler methods that are annotated with @RequestMapping can have very flexible signatures. Most of them can be used in arbitrary order (see below for more details).

  • Request or response objects (Servlet API).Choose any specific request or response type, for example Servlet Request or Http Servlet Request.
  • Session object (Servlet API): of type Http Session. An argument of this type enforces the presence of a corresponding session. As a consequence, such an argument is never null.
  • org. spring frame work. web.context. request. Web Request or org. spring frame work. web. context. request.Native Web Request. Allows for generic request parameter access as well as request/session attribute access, without ties to the native Servlet/Portlet API.
  • java.util.Locale for the current request locale, determined by the most specific locale resolver available, in effect, the configured LocaleResolver in a Servlet environment.
  • java.io.InputStream / java.io.Reader for access to the request's content. This value is the raw InputStream/Reader as exposed by the Servlet API.
  • java.io.OutputStream / java.io.Writer for generating the response's content. This value is the raw Output Stream/Writer as exposed by the Servlet API.
  • @Path Variable annotated parameters for access to URI template variables.
  • @Request Param annotated parameters for access to specific Servlet request parameters. Parameter values are converted to the declared method argument type.
  • @Request Header annotated parameters for access to specific Servlet request HTTP headers. Parameter values are converted to the declared method argument type.
  • @Request Body annotated parameters for access to the HTTP request body.Parameter values are converted to the declared method argument type using Http Message Converters.
  • HttpEntity<?> parameters for access to the Servlet request HTTP headers and contents. The request stream will be converted to the entity body using HttpMessageConverters.
  • java.util.Map / org.springframework.ui.Model / org. spring frame work. ui. Model Map for enriching the implicit model that is exposed to the web view.
  • Command or form objects to bind parameters to: as bean properties or fields, with customizable type conversion, depending on @Init Binder methods and/or the Handler Adapter configuration. See the web Binding Initializer property on Annotation Method Handler Adapter. Such command objects along with their validation results will be exposed as model attributes by default, using the non-qualified command class name in property notation. For example, "orderAddress" for type "mypackage.OrderAddress". Specify a parameter-level ModelAttribute annotation for declaring a specific model attribute name.
  • org. spring frame work.validation.Errors / org. spring frame work.validation.Binding Result validation results for a preceding command or form object (the immediately preceding method argument).
  • org. spring frame work. web. bind. support. Session Status status handle for marking form processing as complete, which triggers the cleanup of session attributes that have been indicated by the @SessionAttributes annotation at the handler type level.

The Errors or Binding Result parameters have to follow the model object that is being bound immediately as the method signature might have more that one model object and Spring will create a separate Binding Result instance for each of them so the following sample won't work:

@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet,
Model model, BindingResult result) { … }

Note, that there is a Model parameter in between Pet and BindingResult. To get this working you have to reorder the parameters as follows:

@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet,
BindingResult result, Model model) { … }

The following return types are supported for handler methods:

  • A Model And View object, with the model implicitly enriched with command objects and the results of @Model Attribute annotated reference data accessor methods.
  • A Model object, with the view name implicitly determined through a Request To View Name Translator and the model implicitly enriched with command objects and the results of @Model Attribute annotated reference data accessor methods.
  • A Map object for exposing a model, with the view name implicitly determined through a Request To View Name Translator and the model implicitly enriched with command objects and the results of @Model Attribute annotated reference data accessor methods.
  • A View object, with the model implicitly determined through command objects and @Model Attribute annotated reference data accessor methods. The handler method may also programmatically enrich the model by declaring a Model argument (see above).
  • A String value that is interpreted as the logical view name, with the model implicitly determined through command objects and @Model Attribute annotated reference data accessor methods.The handler method may also programmatically enrich the model by declaring a Model argument (see above).
  • void if the method handles the response itself (by writing the response content directly, declaring an argument of type Servlet Response / Http Servlet Response for that purpose) or if the view name is supposed to be implicitly determined through a Request To View Name Translator (not declaring a response argument in the handler method signature).
  • If the method is annotated with @Response Body, the return type is written to the response HTTP body. The return value will be converted to the declared method argument type using Http Message Converters.
  • A HttpEntity<?> or Response Entity<?> object to provide access to the Servlet reponse HTTP headers and contents. The entity body will be converted to the response stream using Http Message Converters.
  • Any other return type is considered to be a single model attribute to be exposed to the view, using the attribute name specified through @Model Attribute at the method level (or the default attribute name based on the return type class name). The model is implicitly enriched with command objects and the results of @Model Attribute annotated reference data accessor methods.

Binding request parameters to method parameters with @RequestParam

Use the @RequestParam annotation to bind request parameters to a method parameter in your controller.

The following code snippet shows the usage:

@Controller
@RequestMapping("/pets")
@SessionAttributes("pet")
public class EditPetForm {
// ...
@RequestMapping(method = RequestMethod.GET)
public String setupForm(@RequestParam("petId") int petId, ModelMap model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet);
return "petForm";
}
// ...

Parameters using this annotation are required by default, but you can specify that a parameter is optional by setting @Request Param's required attribute to false (e.g., @Request Param(value= "id", required=false)).

Mapping the request body with the @Request Body annotation

The @Request Body method parameter annotation indicates that a method parameter should be bound to the value of the HTTP request body.For example:

@Request Mapping(value = "/something", method = Request Method.PUT)
public void handle(@RequestBody String body, Writer writer) throws IOException {
writer.write(body);
}

You convert the request body to the method argument by using an Http Message Converter.Http Message Converter is responsible for converting from the HTTP request message to an object and converting from an object to the HTTP response body. Dispatcher Servlet supports annotation based processing using the Default Annotation Handler Mapping and Annotation Method Handle rAdapter. In Spring 3.0 the Annotation Method Handler Adapter is extended to support the @Request Body and has the following Http Message Converters registered by default:

  • Byte Array Http MessageConverter converts byte arrays.
  • String Http MessageConverter converts strings.
  • Form Http MessageConverter converts form data to/from a MultiValueMap<String, String>.
  • Source Http MessageConverter converts to/from a javax.xml.transform.Source.
  • Marshalling Http MessageConverter converts to/from an object using the

The Marshalling Http Message Converter requires a Marshaller and Un marshaller from the org.springframework.oxm package to be configured on an instance of Annotation Method Handler Adapter in the application context. For example:

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<util:list id="beanList">
<ref bean="stringHttpMessageConverter"/>
<ref bean="marshallingHttpMessageConverter"/>
</util:list>
</property
</bean>
<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean id="marshallingHttpMessageConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="castorMarshaller" />
<property name="unmarshaller" ref="castorMarshaller" />
</bean>
<bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/>

Mapping the response body with the @ResponseBody annotation

The @Response Body annotation is similar to @Request Body. This annotation can be put on a method and indicates that the return type should be written straight to the HTTP response body (and not placed in a Model, or interpreted as a view name). For example:

@RequestMapping(value = "/something", method = RequestMethod.PUT)
@ResponseBody
public String helloWorld() {
return "Hello World";
}

The above example will result in the text Hello World being written to the HTTP response stream. As with @RequestBody, Spring converts the returned object to a response body by using an Http Message Converter.

Using HttpEntity<?>

The Http Entity is similar to @RequestBody and @Response Body.Besides getting access to the request and response body, Http Entity (and the response-specific subclass Response Entity) also allows access to the request and response headers, like so:

@RequestMapping("/something")
public ResponseEntity<String> handle(HttpEntity<
byte[]> requestEntity) throws UnsupportedEncodingException {
String requestHeader = requestEntity.getHeaders(). getFirst("MyRequestHeader"));
byte[] requestBody = requestEntity.getBody();
// do something with request header and body
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeader", "MyValue");
return new ResponseEntity<String>("Hello World", responseHeaders, HttpStatus.CREATED);
}

The above example gets the value of the "My Request Header" request header, and reads the body as a byte array. It adds the "My Response Header" to the response, writes Hello World to the response stream, and sets the response status code to 201 (Created).

As with @Request Body and @Response Body, Spring uses Http Message Converter to convert from and to the request and response streams.

Providing a link to data from the model with @ModelAttribute

@Model Attribute has two usage scenarios in controllers. When you place it on a method parameter, @Model Attribute maps a model attribute to the specific, annotated method parameter (see the process Submit() method below).This is how the controller gets a reference to the object holding the data entered in the form.

You can also use @Model Attribute at the method level to provide reference data for the model (see the populate Pet Types() method in the following example).For this usage the method signature can contain the same types as documented previously for the @RequestMapping annotation.

The following code snippet shows these two usages of this annotation:

@Controller
@RequestMapping("/owners/{ownerId}/pets/{petId}/edit")
@SessionAttributes("pet")
public class EditPetForm {
// ...
@ModelAttribute("types")
public Collection<PetType> populatePetTypes() {
return this.clinic.getPetTypes();
}
@RequestMapping(method = RequestMethod.POST)
public String processSubmit(
@ModelAttribute("pet") Pet pet,
BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
return "petForm";
}
else {
this.clinic.storePet(pet);
status.setComplete();
return "redirect:owner.do?ownerId=" + pet.getOwner().getId();
}
}
}

Specifying attributes to store in a session with @SessionAttributes

The type-level @SessionAttributes annotation declares session attributes used by a specific handler. This will typically list the names of model attributes or types of model attributes which should be transparently stored in the session or some conversational storage, serving as form-backing beans between subsequent requests.

The following code snippet shows the usage of this annotation, specifying the model attribute name:

@Controller
@RequestMapping("/editPet.do")
@SessionAttributes("pet")
public class EditPetForm {
// ...
}
Mapping cookie values with the @CookieValue annotation

The @CookieValue annotation allows a method parameter to be bound to the value of an HTTP cookie.

Let us consider that the following cookie has been received with an http request:JSESSIONID= 415A4AC178C 59DACE0B2C9CA727CDD84.

The following code sample demonstrates how to get the value of the JSESSIONID cookie:

@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie) {
//...
}

This annotation is supported for annotated handler methods in Servlet and Portlet environments.

Mapping request header attributes with the @RequestHeader annotation

The @Request Header annotation allows a method parameter to be bound to a request header. Here is a sample request header:

Host localhost:8080
Accept text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300

The following code sample demonstrates how to get the value of the Accept-Encoding and Keep-Alive headers:

@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo (@RequestHeader("Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive") long keepAlive) {
//...
}

This annotation is supported for annotated handler methods in Servlet and Portlet environments.

Customizing WebDataBinder initialization

To customize request parameter binding with Property Editors through Spring's Web Data Binder, you can use either @InitBinder-annotated methods within your controller or externalize your configuration by providing a custom Web Binding Initializer.

Customizing data binding with @InitBinder

Annotating controller methods with @Init Binder allows you to configure web data binding directly within your controller class.@Init Binder identifies methods that initialize the Web Data Binder that will be used to populate command and form object arguments of annotated handler methods.Such init-binder methods support all arguments that @Request Mapping supports, except for command/form objects and corresponding validation result objects.Init-binder methods must not have a return value. Thus, they are usually declared as void. Typical arguments include Web Data Binder in combination with Web Request or java.util.Locale, allowing code to register context-specific editors.

The following example demonstrates the use of @InitBinder to configure a CustomDateEditor for all java.util.Date form properties.

@Controller
public class MyFormController {
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
// ...
}

Configuring a custom Web Binding Initializer

To externalize data binding initialization, you can provide a custom implementation of the Web Binding Initializer interface, which you then enable by supplying a custom bean configuration for an Annotation Method Handler Adapter, thus overriding the default configuration.

The following example from the PetClinic application shows a configuration using a custom implementation of the Web Binding Initializer interface, org. spring frame work. samples. petclinic. web. Clinic Binding Initializer, which configures Property Editors required by several of the PetClinic controllers.

<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="cacheSeconds" value="0" />
<property name="webBindingInitializer">
<bean class="org.springframework.samples.petclinic.web.ClinicBindingInitializer" />
</property>
</bean>

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Java-Springs Topics