This topic is one of many topics that are covered in Spring Framework codecamp >
•
javapassion.com/codecamps
Spring framework topics >
> > >
> > >
Spring DI basics, Spring DI advanced, Spring DI annotation Spring MVC basics, form handling, Ajax, REST, Views Spring Webflow Spring database access (JDBC, Hibernate, JPA), transaction Spring AOP, Spring security, Spring testing Spring JMS, Spring JMX Spring Roo
What is Spring MVC? •
MVC-based Web application framework that takes advantage of design principles of Spring framework > > >
Controller, validator, command object, form object, model object, DispatcherServlet, handler mapping, view resolver, and so on -- can be fulfilled by a specialized object and replaceable without affecting others
Powerful and straightforward configuration of both framework and application classes as JavaBeans Adaptability, non-intrusiveness, and flexibility >
Define any controller method signature you need, possibly using one of the parameter annotations (such as @RequestParam, @RequestHeader, @PathVariable, and more) for a given scenario
Features of Spring Web MVC (Continued) •
•
Customizable binding (conversion) and validation Customizable handler mapping and view resolution >
•
Flexible model transfer >
• •
Handler mapping and view resolution strategies range from simple URL-based configuration, to sophisticated, purpose-built resolution strategies. Model transfer with a name/value Map supports easy integration with any view technology
Customizable locale and theme resolution A simple yet powerful JSP tag library known as the Spring tag library
DispatcherServlet
DispatcherServlet •
It plays the role of Front controller in Spring MVC > >
Coordinates the HTTP request life-cycle Configured in web.xml
Sequence of HTTP Request Handling 1.DispatchServlet receives a HTTP request 2.DispatchServlet selects a Controller based on the URL Handler mapping and pass the request to the Controller 3.Controller (actually handler in a Controller) performs the business logic and set values of Model objects 4.Controller returns a logical view 5.A ViewResolver, which provides a particular view (JSP, PDF, Excel, etc.), is selected 6.A view gets displayed using values of Model objects
DispatcherServlet Configuration •
Configured in the “web.xml” file as a regular servlet exampleexample ervlet-name> org.springframework.web.ser org.springfram ework.web.servlet.DispatcherServlet vlet.DispatcherServlet 1exampleexample ervlet-name> /
Spring Context Configuration
Typical Configuration Setup •
Two Spring bean containers (or ApplicationContexts) initialized - not mandatory >
>
1 “root” context to host “shared resources” required by servlets/filters/services 1 “web” context to host local application components delegated by the DispatchServlet
Key features of the Spring MVC are modularized through Spring MVC interfaces >
>
•
Custom implementations can be created and configured This is how Spring framework itself can be extended and customized
Spring framework comes with built-in implementations of the interfaces >
Default implementation is pre-selected for most common cases
Spring MVC Interfaces •
HandlerMapping >
•
ViewResolver >
•
Maps symbolic name to view
HandlerExceptionResolver > >
•
Routing of requests to handlers (controllers)
Maps exceptions to error pages Similar to standard Servlet, but more flexible
LocaleResolver >
Selects locale based on HTTP accept header, cookie
Controllers
What does a Controller do? •
Controllers provide access to the business logic >
>
•
Typically a controller delegates business logic processing to a set of services The services in turn access database through Dao interface
Controllers interpret user input and transform it into a model and set attributes (key/value pairs) of the model as a result of business logic
Controllers: Annotation-based Controllers
Annotation-based Controllers •
In pre-Spring 2.5, you had to extend Springspecific base controller classes > >
•
SimpleFormController, MultiActionController, etc Your controller code is tied up with framework - they are not POJO's
Spring 2.5 introduced an annotation-based controllers >
>
>
Annotation-based controllers do not have to extend specific base controller classes or implement specific interfaces. Annotation-based controllers do not usually have direct dependencies on Servlet or Portlet APIs either Annotation-based controllers are POJO's
Annotation-based Controller // Annotation-based Controller do not have // to extend specific Spring base classes or implement // specific interfaces. @Controller public class HelloWorldController {
}
// There is no constraint to the method signature either @RequestMapping("/helloWorld") public ModelAndView helloWorld() { ModelAndView mav = new ModelAndView(); mav.setViewName("helloWorld"); // set the view mav.addObject("message", "Hello World!"); return mav; }
Auto-detection of Annotated Controllers •
Through component scanning, all annotated controller beans are automatically detected - there is no need to declare them in the context configuration file
// ...
Controllers: Mapping Requests to Handlers with @RequestMapping
Mapping requests with @RequestMapping •
@RequestMapping annotation is used to map URLs such as /appointments onto a class (when used over a class) or a particular handler method (when used over a method)
Mapping requests with @RequestMapping @Controller @RequestMapping("/appointments") public class AppointmentsController { private final AppointmentBook appointmentBook; @Autowired public AppointmentsController(AppointmentBook appointmentBook) { this.appointmentBook = appointmentBook; } // Handle http://locahost:8080/myapp/appointments @RequestMapping(method = RequestMethod.GET) public Map get() { return appointmentBook.getAppointmentsForToday(); } // Handle http://locahost:8080/myapp/appointments/4 or // http://locahost:8080/myapp/appointments/5 @RequestMapping(value="/{day}", method = RequestMethod.GET) public Map getForDay ( @PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) { return appointmentBook.getAppointmentsForDay(day);
@RequestMapping for Form Handling // Continued from previous slide // Handles http://locahost:8080/myapp/appointments/new // Display initial form @RequestMapping(value="/new", method = RequestMethod.GET) public AppointmentForm getNewForm() { return new AppointmentForm(); }
}
// Handles http://locahost:8080/myapp/appointments/new // Handle form submission @RequestMapping(value="/new", method = RequestMethod.POST) public String add(@Valid AppointmentForm appointment, BindingResult result) { if (result.hasErrors()) { return "appointments/new"; } appointmentBook.addAppointment(appointment); return "redirect:/appointments"; }
We will cover “form handling” in detail in another presentation and hands-on lab - “spring3_mvc_form”.
@RequestMapping Only at Method Levels // A @RequestMapping on the class level is not required. Without it, all paths // are simply absolute, and not relative. @Controller public class ClinicController { private final Clinic clinic; @Autowired public ClinicController(Clinic clinic) { this.clinic = clinic; } // Handles http://locahost:8080/myapp/ @RequestMapping("/") public void welcomeHandler() { } // Handles http://locahost:8080/myapp/vets @RequestMapping("/vets") public ModelMap vetsHandler() { return new ModelMap(this.clinic.getVets()); }
Controllers: URI Template
What is URI Template? •
A URI Template is a URI-like string, containing one or more variable names >
Variables are in the form of {nameOfVariable}
@RequestMapping(value="/owners/ {ownerId}")) •
When you substitute values for these variables, the template becomes a concrete URI. /owners/3 /owners/5
•
The request URI is compared to an matching URI Template
URI Template Example #1 // Suppose the request URL is http://locahost:8080/myapp/owners/3, // the value 3 will be captured as “ownerId” argument in String type.
@RequestMapping(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"; }
URI Template Example #2 // You can use multiple @PathVariable annotations to bind to multiple URI // Template variables. // Suppose the request URL is http://locahost:8080/myapp/owners/3/pets/5, // the value 3 will be captured as “ownerId” argument in String type while // the value 5 will be captured as “petId” argument in String type.
@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"; }
URI Template Example #3 // You can use multiple @PathVariable annotations to bind to multiple URI // Template variables @Controller @RequestMapping("/owners/{ownerId}") public class RelativePathUriTemplateController { @RequestMapping("/pets/{petId}") public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // implementation omitted } }
Controllers: Mapping Requests with Other Means
Mappings through parameter conditions // 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. @Controller @RequestMapping("/owners/{ownerId}") public class RelativePathUriTemplateController { // Handles http://locahost:8080/myapp/owners/3/pets/5?myParam=myValue @RequestMapping(value = "/pets/{petId}", params="myParam=myValue") public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // implementation omitted } }
Mappings through HTTP header conditions // The addPet() method is only invoked when the content-type matches the // text/* pattern, for example, text/xml @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 } }
Controllers: Handler Method Arguments
Objects that are auto-created by Spring • •
You can simply use these as handler arguments Request or response objects (Servlet API) >
•
Session object (Servlet API) >
•
HttpSession
java.util.Locale >
•
ServletRequest or HttpServletRequest
For the current request locale, determined by the most specific locale resolver available
java.security.Principal >
Currently authenticated user
@PathVariable & @RequestParam •
@PathVariable >
>
Annotated parameters for access to URI template variables Extracts data from the request URI >
>
•
http://host/catalog/items/123
Parameter values are converted to the declared method argument type
@RequestParam(“namex”) >
>
Annotated parameters for access to specific Servlet request parameters. Extracts data from the request URI query parameters >
>
http://host/catalog/items/?namex=abc
Parameter values are converted to the declared method argument type
@PathVariable - For URI Path Values // Use the @PathVariable annotation to bind URI path value to a method // parameter in your controller. @Controller @RequestMapping("/pets") public class MyPetClass { // ... // Will handle ../pets/4 or ../pets/10 @RequestMapping(method = RequestMethod.GET) public String getData(@PathVariable int petId, ModelMap model) { Pet pet = this.clinic.loadPet(petId); model.addAttribute("pet", pet); return "petForm"; } // ...
@RequestParam - For Query Parameters // Use the @RequestParam annotation to bind query request parameters to a // method parameter in your controller. @Controller @RequestMapping("/pets") public class MyPetClass { // ... // Will handle ../pets?petId=4 or ../pets?petId=10 @RequestMapping(method = RequestMethod.GET) public String getData(@RequestParam("petId") int petId, ModelMap model) { Pet pet = this.clinic.loadPet(petId); model.addAttribute("pet", pet); return "petForm"; } // ...
Request Header and Body •
@RequestHeader(“name”) >
•
Annotated parameters for access to specific Servlet request HTTP headers
@RequestBody >
>
Annotated parameters for access to the HTTP request body. Parameter values are converted to the declared method argument type using HttpMessageConverter's
@RequestBody // The @RequestBody method parameter annotation indicates that a method // parameter should be bound to the value of the HTTP request body. @RequestMapping(value = "/something", method = RequestMethod.PUT) public void handle(@RequestBody String body, Writer writer) throws IOException { writer.write(body); }
View can access these models after attributes of these models are set in the handler methods
Model types that are allowed > >
java.util.Map org.springframework.ui.Model >
>
Holder of attributes
org.springframework.ui.ModelMap >
Supports chained calls and auto-generation of model attribute names.
Model object as Handler argument @RequestMapping(value = "/hotels-search", method = RequestMethod.GET) public String list(SearchCriteria criteria, Model model) { // Using the "SearchCriteria", perform the search through // "bookingService". List hotels = bookingService.findHotels(criteria); // Add an attribute to the model. The view now can access // “hotelList” through ${hotelList} notation model.addAttribute(“hotelList”, hotels);
}
// Return logical view name "hotels/list", which results in displaying // "hotels/list.jsp". return "hotels/list";
ModelMap object as Handler argument @RequestMapping("/deposit.do") protected String deposit( @RequestParam("accountNo") int accountNo, @RequestParam("amount") double amount, ModelMap modelMap) {
}
accountService.deposit(accountNo, amount); // Chaining is allowed for ModelMap object modelMap.addAttribute("accountNo", accountNo) .addAttribute("balance", accountService.getBalance(accountNo)); return "success";
Controllers: HttpMessageConverters
HttpMessageConverter's •
•
•
•
•
Behind the scene, a HttpMessageConverter is involved for reading request body and generating response body Different converters are registered for different content types For @RequestBody, the first converter that can read the POSTed “Content-Type” into the desired method parameter type is used For @ResponseBody, the first converter that can write the method return type into one of the client's “Accept”'ed content type is used Default set of HttpMessageConverters are registered for you
Default HttpMessageConverters •
StringHttpMessageConverter > >
•
FormHttpMessageConverter >
>
•
Reads “text/*” into Strings (for request) Writes Strings as “text/plain” (for response) Reads “application/x-www-form-urlencoded” into MultiValueMap (for request) Writes MultiValueMap into “application/x-www-form-urlencoded” (for response)
ByteArrayMessageConverter > >
Reads “*/*” into a byte[] writes Objects as “application/octet-stream”
Controllers: Handler Method Return Types
ModelAndView Object public class DisplayShoppingCartController implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { List cartItems = // get a List of CartItem objects User user = // get the User doing the shopping ModelAndView mav = new ModelAndView("displayShoppingCart"); //logical view name mav.addObject(cartItems); // look ma, no name, just the object mav.addObject(user); // and again ma! }
return mav;
String (Logical View Name - Most Popular) •
Is interpreted as the logical view name, with the model implicitly determined through command objects and @ModelAttribute annotated reference data accessor methods // Logical view is returned as “view/html” @RequestMapping(value="html", method=RequestMethod.GET) public String prepare(Model model) { model.addAttribute("foo", "bar"); model.addAttribute("fruit", "apple"); return "views/html"; }
void •
Used in two situations >
>
#1: when the method handles the response itself (by writing the response content directly, declaring an argument of type ServletResponse / HttpServletResponse for that purpose) #2: When the view name is supposed to be implicitly determined through a RequestToViewNameTranslator
// #2: The view name is implicitly set to “viewNameX” @RequestMapping(value="/viewNameX", method=RequestMethod.GET) public void usingRequestToViewNameTranslator(Model model) { model.addAttribute("foo", "bar"); model.addAttribute("fruit", "apple"); }
@ResponseBody annotated Method •
If the method is annotated with @ResponseBody , the return type is written to the response HTTP body @RequestMapping(value="/response/annotation", method=RequestMethod.GET) public @ResponseBody String responseBody() { return "The String ResponseBody"; }
A HttpEntity> or ResponseEntity> •
•
Provide access to the Servlet reponse HTTP headers and contents. The entity body will be converted to the response stream using HttpMessageConverter @RequestMapping(value="/response/entity/headers", method=RequestMethod.GET) public ResponseEntity responseEntityCustomHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); return new ResponseEntity("The String ResponseBody with custom header Content-Type=text/plain", headers, HttpStatus.OK); }
Controllers: @SessionAttributes
@SessionAttributes •
•
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 formbacking beans between subsequent requests.
@SessionAttributes @Controller @RequestMapping("/editPet.do") @SessionAttributes("pet") public class EditPetForm { // ... }
Handler Mapping Customization
DefaultAnnotationHandlerMapping •
•
In pre-2.5 versions of Spring, users were required to define HandlerMappings in the web application context to map incoming web requests to appropriate handlers. From Spring 2.5, the DispatcherServlet enables the DefaultAnnotationHandlerMapping as a default >
>
DefaultAnnotationHandlerMapping searches for @RequestMapping annotations on @Controllers Typically, you do not need to override this default mapping, unless you need to override the default property values for customization
Handler Mapping Properties • •
interceptors defaultHandler >
•
Default handler to use, when this handler mapping does not result in a matching handler.
order
Handler Mappings: Interceptor
Add an “interceptor” to default mapping // This example shows how to override the default mapping and add an // interceptor:
What Do Interceptors Do? •
Interceptors are useful when you want to apply specific functionality to certain requests >
•
Authentication, authorization, logging, etc
Interceptors must implement HandlerInterceptor interface >
>
boolean preHandler(..) method - When this method returns true, the handler execution chain will continue; when it returns false, the DispatcherServlet assumes the interceptor itself has taken care of requests (and, for example, rendered an appropriate view) and does not continue executing the other interceptors and the actual handler in the execution chain void postHandler(..) method
Interceptor Example #1 - Java Code public class LoggingInterceptor extends HandlerInterceptorAdapter { private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class); public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { logger.info("LoggingInterceptor: preHandle() entered"); return true; }
Interceptor Example #2 package samples; public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { ... public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
}
}
Calendar cal = Calendar.getInstance(); int hour = cal.get(HOUR_OF_DAY); if (openingTime <= hour < closingTime) { return true; } else { response.sendRedirect("http://host.com/outsideOfficeHours.html"); return false; }
Interceptor Example #2 - Configuration /*.form=editAccountFormController /*.view=editAccountFormController
Views vs. @ResponseBody
Two Schemes of Rendering Response •
Two schemes for rendering response > >
•
They are triggered in different ways > >
•
ViewResolver + View HttpMessageConverter Render a view by returning a logical view String Write a message by returning a @ResponseBody or ResponseEntity
Which one to use? >
>
Use ViewResolver + View to generate documents for display in a web browser - HTML, PDF, etc Use @ResponseBody to exchange data with web service clients - JSON, XML, etc
Resolving Views
Resolving Views •
All handler methods in the Spring Web MVC controllers must resolve to a logical view name >
>
•
•
Explicitly (e.g., by returning a String, View, or ModelAndView) or Implicitly (i.e., based on conventions)
Views in Spring are addressed by a logical view name and are resolved by a view resolver Spring comes with quite a few view resolvers
UrlBasedViewResolver // A simple implementation of the ViewResolver interface that effects the direct // resolution of symbolic view names to URLs, without an explicit mapping // definition. This is appropriate if your symbolic names match the names of // your view resources in a straightforward manner, without the need for // arbitrary mappings. // When returning test as a logical view name, this view resolver forwards // the request to the RequestDispatcher that will send the request to // /WEB-INF/jsp/test.jsp.
InternalResourceViewResolver // A convenience subclass of UrlBasedViewResolver that supports // InternalResourceView (i.e. Servlets and JSPs), and subclasses such // as JstlView and TilesView.
ResourceBundleViewResolver // The ResourceBundleViewResolver inspects the ResourceBundle identified // by the basename , and for each view it is supposed to resolve, it uses the value // of the property [viewname].(class) as the view class and the value of the // property [viewname].url as the view url.
resource bundle # views.properties file in the classpath welcomeRedirect.(class)=org.springframework.web.servlet.view.RedirectView welcomeRedirect.url=welcome.jsp reservationSuccessRedirect. (class)=org.springframework.web.servlet.view.RedirectView reservationSuccessRedirect.url=reservationSuccess.jsp reservationSummary.(class)=com.javapassion.examples.views.ExcelReservation
Resolving Views: Chaining ViewResolvers
Chaining ViewResolver's •
You chain view resolvers by adding more than one resolver to your application context and, if necessary, by setting the order property to specify ordering. >
>
•
The higher the order property, the later the view resolver is positioned in the chain InternalResourceViewResolver is automatically positioned as the last ViewResolver
If a specific view resolver does not result in a view, Spring continues to inspect them until a view is resolved
Chaining ViewResolver's // In the following example, the chain of view resolvers consists of two resolvers, // an InternalResourceViewResolver , which is always automatically positioned as // the last resolver in the chain, and an XmlViewResolver for specifying Excel // views. Excel views are not supported by the InternalResourceViewResolver.
Type Conversion
Type Conversion • •
Type conversion happens automatically A common “ConversionService” used in the places where type conversion is required > >
Convention over Configuration Support: Automatic Key name Generation in ModelMap ModeAndView
ModelMap & ModelAndView Classes •
•
The ModelMap class is essentially a glorified Map that can make adding objects that are to be displayed in (or on) a View adhere to a common naming convention The ModelAndView class uses a ModelMap class that is a custom Map implementation that automatically generates a key for an object when an object is added to it.
Automatic Key Generation for ModelAndView public class DisplayShoppingCartController implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { List cartItems = // get a List of CartItem objects User user = // get the User doing the shopping // “displayShoppingCart” is logical view ModelAndView mav = new ModelAndView("displayShoppingCart"); mav.addObject(cartItems); // “cartList” is automatically generated as a key mav.addObject(user); //”user” is automatically generated as a key
}
}
return mav;
Key Name Generation Strategy •
Scalar object - use the short class name of the object's class > >
•
x.y.User instance added will have the name user x.y.Registration instance added will have the name registration
Collection object >
>
>
An x.y.User[] array with one or more x.y.User elements added will have the name userList An x.y.Foo[] array with one or more x.y.User elements added will have the name fooList A java.util.ArrayList with one or more x.y.User elements added will have the name userList
Convention over Configuration Support: Logical View Name Generation
Handler Without Setting Logical View // A request URL of http://localhost/registration.html results in a logical view // name of registration being generated by the // DefaultRequestToViewNameTranslator. This logical view name is then // resolved into the /WEB-INF/jsp/registration.jsp view by the // InternalResourceViewResolver bean. public class RegistrationController implements Controller {
}
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) { // process the request... ModelAndView mav = new ModelAndView(); // add data as necessary to the model... return mav; // notice that no View or logical view name has been set }
Configuration for Logical View Name Generation (This is done for you)
Spring 3 Configuration
Spring 3 Enhancement •
Spring 3 introduces a mvc XML configuration namespace that simplifies the setup of Spring MVC inside your web application. >
>
Instead of registering low-level beans such as AnnotationMethodHandlerAdapter , you can simply use the namespace and its higher-level constructs. This is generally preferred unless you require finergrained control of the configuration at the bean level.
Tags in Namespace • • • • •
•
•
This tag registers the DefaultAnnotationHandlerMapping and AnnotationMethodHandlerAdapter beans that are required for Spring MVC to dispatch requests to @Controllers. The tag configures those two beans with sensible defaults based on what is present in your classpath.
Defaults •
•
•
Support for Spring 3's Type ConversionService in addition to JavaBeans PropertyEditors during Data Binding. Support for formatting Number fields using the @NumberFormat annotation Support for formatting Date, Calendar, Long, and Joda Time fields using the @DateTimeFormat annotation, if Joda Time 1.3 or higher is present on the classpath.
Defaults •
• •
Support for validating @Controller inputs with @Valid, if a JSR-303 Provider is present on the classpath. The validation system can be explicitly configured by setting the validator attribute. Support for reading and writing XML Support for reading and writing JSON
Example
•
•
•
This tag is a shorcut for defining a ParameterizableViewController that immediately maps incoming request to a view Use it in static cases when there is no Java Controller logic to execute before the view generates the response Example
from 3.0.4 •
•
•
Provides a convenient way to serve static resources from locations other than the web application root, including locations on the classpath The cache-period property may be used to set far future expiration headers Example
from 3.0.4 •
•
•
•
Allows for mapping the DispatcherServlet to "/" (thus overriding the mapping of the container's default Servlet), while still allowing static resource requests to be handled by the container's default Servlet. It configures a DefaultServletHttpRequestHandler with a URL mapping (given a lowest precedence order) of "/**". This handler will forward all requests to the default Servlet. Example
Example
Logging
log4j.xml
log4j.properties # For JBoss: Avoid to setup Log4J outside $JBOSS_HOME/server/default/deploy/log4j.xml! # For all other servers: Comment out the Log4J listener in web.xml to activate Log4J. #log4j.rootLogger=INFO, stdout, logfile log4j.rootLogger=ERROR, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n #log4j.appender.logfile=org.apache.log4j.RollingFileAppender #log4j.appender.logfile.File=${mvc_basics_form.root}/WEB-INF/mvc_basics_form.log #log4j.appender.logfile.MaxFileSize=512KB # Keep three backup files. #log4j.appender.logfile.MaxBackupIndex=3 # Pattern to output: date priority [category] - message #log4j.appender.logfile.layout=org.apache.log4j.PatternLayout #log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n log4j.logger.org.springframework.web=DEBUG