Spring MVC Abstract Controller example
For self-reference, this article shows you how to create a Abstract
class for Spring Controller, or a template method design pattern.
1. Abstract Controller
In Abstract class, the @Controller
annotation is optional, your implemented class will apply it.
AbstractResultController.java
package com.mkyong.web.controller;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.mkyong.web.generator.bo.ResultGenerator;
public abstract class AbstractResultController {
private final Logger logger = LoggerFactory.getLogger(getClass());
abstract ResultGenerator GetResultGenerator();
abstract String GetViewName();
abstract Validator GetValidator();
@RequestMapping(value = "/{q:.+}", method = RequestMethod.GET)
final ModelAndView getModelAndView(@PathVariable("q") String q) {
logger.debug("getModelAndView : [q] : {}", q);
ModelAndView model = new ModelAndView();
Map<String, Object> results = GetResultGenerator().getResultForController(q);
model.addObject("data", results);
model.setViewName(GetViewName());
logger.debug("getModelAndView : [model] : {}", model);
return model;
}
}
2. Spring Controllers Extend Abstract
Few Spring controllers extend above Abstract class and their matched URI path.
2.1 Path = /hosting/{q:.+}
ResultControllerHosting.java
package com.mkyong.web.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.mkyong.web.generator.bo.ResultGenerator;
@Controller
@RequestMapping("/hosting")
public class ResultControllerHosting extends AbstractResultController {
private static final String VIEW_NAME = "hosting";
@Autowired
@Qualifier("resultGeneratorHosting")
ResultGenerator resultGenerator;
@Override
ResultGenerator GetResultGenerator() {
return resultGenerator;
}
@Override
String GetViewName() {
return VIEW_NAME;
}
}
2.2 Path = /site/{q:.+}
ResultControllerSite.java
package com.mkyong.web.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.mkyong.web.generator.bo.ResultGenerator;
@Controller
@RequestMapping("/site")
public class ResultControllerSite extends AbstractResultController {
private static final String VIEW_NAME = "site";
@Autowired
@Qualifier("resultGeneratorSite")
ResultGenerator resultGenerator;
@Override
ResultGenerator GetResultGenerator() {
return resultGenerator;
}
@Override
String GetViewName() {
return VIEW_NAME;
}
}
Done.
with this approach, we were still able to access the method in AbstractResultContainer.getModelAndView using 2 routes
a.) using /{q:.+}
b.) using /site/{q:.+}
can we by anyway make ONLY one route “/site/{q:.+}” to work ?
1. In AbstractResultContainer, comment //@RequestMapping
2. In “site” class, create a method and annotate with @RequestMapping{q:.+} , and call the abstract method manually. So does “hosting” class.
could you share this example?
Why do you use the uppercase letter for GetResultGenerator? 🙂
Hi mkyong, Where is the code for ResultGenerator and Validator?
Hi, can the abstract class has @Autowired members?
members relevant to all sub-classes.
Is it possible to map the abstract class,
ex
@RequestMapping(“/someTopLevelMapping”)
public abstract class AbstractResultController
and the classes that extend it to only implement and/or map their methods under it?