Main Tutorials

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

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
7 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
krishna
9 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
8 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
7 years ago
Reply to  mkyong

could you share this example?

ste
1 year ago

Why do you use the uppercase letter for GetResultGenerator? 🙂

Nim
5 years ago

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

Adam Vaanunu
5 years ago

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

Apostolos Palogos
8 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?