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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With