Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing a reusable @Controller

I'm implementing some SQL-CRUD components for Spring-MVC and I'm facing a problem.

I provide a TableController which provides several controller methods:

public class TableController ... {

    public TableController(String tableName) { ... }

    @RequestMapping("/list")
    public ModelAndView list() { ... }

    @RequestMapping("/addForm")
    public ModelAndView addForm() { ... }
    ...

This TableController basically provides functionality over a database table- a controller method that lists the table's rows, forms for creating and updating table rows, etc. It is a somewhat complex class, as it needs to be customizable to offer different behaviour for different tables.

Ideally, I would like users of this controller to be able to add a new instance for each database table they want to expose in their website by adding it to a context, something like this:

@Configuration
class Context {
    @Bean("/vets/")
    public TableController vetController() {
        return new TableController("vets");
    }

    @Bean("/pets/")
    public TableController petController() {
        return new TableController("pets");
    }

I would expect then to get /vets/list, /vets/addForm, /pets/list URLs exposed in their app.

However, this does not work. The only way I've gotten this to work is by not using any @RequestMapping annotation in TableController and having the apps extend TableController for each table they want to expose and define all @RequestMappings in the subclasses, what I'm doing for instance in Application and PetController

This works but it's extremely awkward. Any way to improve this?

Edit: it seems that I'm fucked:

There are also several things no longer possible:

  • Select a controller first with a SimpleUrlHandlerMapping or BeanNameUrlHandlerMapping and then narrow the method based on @RequestMapping annotations.

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-31-vs-30

like image 873
alex Avatar asked May 13 '26 02:05

alex


2 Answers

What you need is only one "@TableController" with dynamic "@RequestMapping". Use a variable, path or request, to identify the database table or entity and build the query accordingly. You can even mix this with the logged in user to build restrictions for example.

@Controller
@RequestMapping("/{tablename}")
public class TableController ... {


    public TableController() { ... }

    @RequestMapping("/list")
    public ModelAndView list(@PathVariable("tablename") String tablename) { ... }

    @RequestMapping("/addForm")
    public ModelAndView addForm(@PathVariable("tablename") String tablename) { ... }
    ...

Read the javadoc of "@RequestMapping" and "@Controller". They support quite a lot of variable types.

like image 188
Martin Frey Avatar answered May 15 '26 16:05

Martin Frey


Have you tried to add the @RequestMapping annotation to the class level of the subclasses? By doing so, the other @RequestMapping annotations in the TableController should become relative. There will still be one class per table, but it becomes really trivial. Example:

// No @RequestMapping on class level
public abstract class TableController {
    // all methods annotated with @RequestMapping that will be relative once inherited
}

First actual controller

@Controller
@RequestMapping("/vets")
public class VetController extends TableController {

    public VetController() {
        super("vets");
    }

    // other methods and relative @RequestMapping omitted since they are inherited from parent class 
}

Second controller

@Controller
@RequestMapping("/pets")
public class PetController extends TableController {

    public PetController() {
        super("pets");
    }

    // other methods and relative @RequestMapping omitted since they are inherited from parent class 
}

More info about the @RequestMapping can be found in Spring's reference documentation.

like image 26
matsev Avatar answered May 15 '26 16:05

matsev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!