COC Web WVC

Convention Over Configuration extension to Spring Web WVC

License

License

Categories

Categories

Net
GroupId

GroupId

net.sf.cocmvc
ArtifactId

ArtifactId

spring-cocmvc-ext
Last Version

Last Version

1.0
Release Date

Release Date

Type

Type

jar
Description

Description

COC Web WVC
Convention Over Configuration extension to Spring Web WVC
Project URL

Project URL

https://github.com/xinthink/cocmvc
Source Code Management

Source Code Management

https://github.com/xinthink/cocmvc

Download spring-cocmvc-ext

How to add to project

<!-- https://jarcasting.com/artifacts/net.sf.cocmvc/spring-cocmvc-ext/ -->
<dependency>
    <groupId>net.sf.cocmvc</groupId>
    <artifactId>spring-cocmvc-ext</artifactId>
    <version>1.0</version>
</dependency>
// https://jarcasting.com/artifacts/net.sf.cocmvc/spring-cocmvc-ext/
implementation 'net.sf.cocmvc:spring-cocmvc-ext:1.0'
// https://jarcasting.com/artifacts/net.sf.cocmvc/spring-cocmvc-ext/
implementation ("net.sf.cocmvc:spring-cocmvc-ext:1.0")
'net.sf.cocmvc:spring-cocmvc-ext:jar:1.0'
<dependency org="net.sf.cocmvc" name="spring-cocmvc-ext" rev="1.0">
  <artifact name="spring-cocmvc-ext" type="jar" />
</dependency>
@Grapes(
@Grab(group='net.sf.cocmvc', module='spring-cocmvc-ext', version='1.0')
)
libraryDependencies += "net.sf.cocmvc" % "spring-cocmvc-ext" % "1.0"
[net.sf.cocmvc/spring-cocmvc-ext "1.0"]

Dependencies

compile (2)

Group / Artifact Type Version
javax.servlet : javax.servlet-api jar 3.1-b02
org.springframework : spring-webmvc jar 3.1.2.RELEASE

test (1)

Group / Artifact Type Version
junit : junit jar 4.10

Project Modules

There are no modules declared in this project.

Convention Over Configuration extension to Spring Web MVC

Why we need this extension

Often, we develope web applications with the powerful Spring Web MVC in these two ways (or both of them):

  1. Convention over configuration support
  • help omitting many 'redundant' configurations
  • but we must have our controllers implementing a framework specific interface, reducing the flexibility
  1. Annotation-driven
  • very powerful request mappings, and flexible handler method declarations
  • but it's actual configurations, sometimes seems to be 'redundant'

Both of them are pretty good, but there's no way to put them together in a single controller, you have to make the choice, and tolerate the redundancy.

But now, with the cocmvc extension, one is allowed to write a controller like this:

// maps to /hello
public class HelloController {
  
  // handling /hello
  public void index(Model modle) {
    modle.addAttribute("this's the home page of hello");
    // view-id = 'hello'
  }
  
  // handling /hello/delete?id=1
  public void delete(@RequestParam("id") int id) {
    ...
    // view-id = 'hello/delete
  }
  
  // handling /hello/show/1
  @RequestMapping("show/{id}")
  public void show(@PathVariable("id") int id) {
    ...
    // view-id = 'hello/show'
  }
}

Well, it combines the advantages of Spring's COC support and annotation-driven together, and I think it's also concise, and DRY.

Let's see how to do that.

Developing by convention

URL pattern

By convention, the URL pattern is:

<context-root>/<module>/<controller>/<action>
  • module
  • modularity, it's a good idea to package controllers into modules in a big application
  • can recursively contain other sub-modules, such as: news/sports/football
  • must provide a basePackage to enable modularity, the relative path (to the basePackage) of a controller will be used as it's module; otherwise, the module part will always be empty ('')
  • controller
  • just like Spring or Grails, controller class named AbcController will be mapped to /abc
  • supports camel-case style (by default) or snake-case style, i.e. helloWorld, or hello-world
  • action
  • mapped to action methods (request handlers), each public method of the controller will be mapped as an action
  • method named index is a special case, it will be treated as the home page of the controller (the / action)
  • also by convention, init and destroy are life-cycle methods of a Spring bean, the framework will NOT treat them as actions
  • you can choose camel-case style (by default) or snake-case style

Controllers

Coding a controller

  • Naming
  • Name your controller class with a 'Controller' suffix, for example: LoginController, UserRegisterController
  • A controller class may extends any base class or implements any interface
  • Packaging
  • You can put your controllers under any packages as you need
  • By setting a basePackage, controllers will be grouped into modules, for example, the module name of basePackage.abc.def.HelloController is 'abc/def', and it will be responsible to the URL /abc/def/hello
  • Write action methods
  • Public methods of a controller are all action methods, including methods inherited from base classes, excluding methods declared in Object, such as toString, hashCode ...
  • You can define an action method in any form supported by Spring Web MVC

Make controller a Spring bean

XML configuration, component scanning ...

Feel free to choose the way most fit to your project, but the component scanning way seems to be more DRY.

View templates

By convention, the view-id of each action is corresponding to the requesting URL, i.e. view-id for action /hello/show is 'hello/show'

So, you can ommit the view-id return value (or when instantiating the ModelAndView), if you comply with the conventional view templates layout

For example (assume you're using jsp):

views                                   Root of your view templates, may be /WEB-INF/views
  |
  |-- <controller>                      Views folder for top-level controllers
  |     |-- <action>.jsp                View templates
  |     \-- ...                 
  |
  |-- <module>                          Views folder for module
  |     |-- <sub-module>                Sub-module, recursively
  |     |     |-- <controller>
  |     |     |     |-- <action>.jsp    
  |     |     |     \-- ...
  |     |     \-- ...
  |     |
  |     |-- <controller>                Views folder for controller
  |     |     |-- <action>.jsp          View templates
  |     |     \-- ...             
  |     \-- ...                  
  |
  |-- index.jsp                         Top-level view templates, home page, error page etc.
  \-- ...

Overrides the convention

You can override the convention by using annotations (configurations).

For example, I'd like the home page located at /, instead of /home

@RequestMapping("/")
public class HomeController {

  // handling /
  public String index() {
    ...
    retrun "index"; // view-id = 'index'
  }
}

or, to use path variables

public class PersonController {

  // handling /person/show
  @RequestMapping("show/{id}")
  public void show(@PathVariable("id") int id) {
    ...
    // view-id = 'person/show'
  }
}

and sometimes, some special public methods should not be treated as actions

public class PersonController {

  @NoMapping
  @ModelAttribute
  public Person addModelAttribute() {
    ...
    return new Person();
  }
}

Project dependencies

Before enjoy developing by convention, you should first add cocmvc to your project dependencies.

Add the following snippet in your gradle build script, or something equivalent in other dependencies management tools:

repositories {
    mavenCentral()
}

dependencies {
    compile 'net.sf.cocmvc:spring-cocmvc-ext:1.0'
}

*please refer to the sample build file

Configurations

Huh, there's also a little configuration job to be done, in order to override the default behavior of Spring framework.

<!-- close spring's annotation-driven to avoid duplicated URL mapping -->
<!--<mvc:annotation-driven />-->

<!-- add this line to make our action methods to be adapted as request Handlers -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />

<!-- Enable conventional developing mode,
  and provides a basePacakge to enabled the modularity feature
-->
<bean class="net.sf.cocmvc.ConventionalHandlerMapping" p:basePackage="com.abc.controller" />

Enjoy!

Please refer to the sample project for more details.

Versions

Version
1.0