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.

References

  1. Oracle Java Tutorial : Abstract Methods and Classes
  2. Spring AbstractController JavaDoc

mkyong

Founder of Mkyong.com, passionate Java and open-source technologies. If you enjoy my tutorials, consider making a donation to these charities.

7 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
krishna
11 years ago

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 ?

mkyong
11 years ago
Reply to  krishna

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.

ttson24
9 years ago
Reply to  mkyong

could you share this example?

ste
3 years ago

Why do you use the uppercase letter for GetResultGenerator? 🙂

Nim
7 years ago

Hi mkyong, Where is the code for ResultGenerator and Validator?

Adam Vaanunu
7 years ago

Hi, can the abstract class has @Autowired members?
members relevant to all sub-classes.

Apostolos Palogos
11 years ago

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?