Suggest MVC frameworks that do not use controller base classes - model-view-controller

Pseudo-code:
class SomeController {
def myAction() {
// controler is an property passed via ctor
controller.redirect(toWhereever)
}
}
// another variant
class AnotherController {
def myAction(controller) {
// controler is an method argument
controller.redirect(toWhereever)
}
}
Any suggestions?
Edit: Because the question is a bit dry you could try to spice up your answers with some experience with the framework and what do you think is better with that approach.

Spring MVC and Grails (built ontop of spring) favour dependency injection with no inheritance whatsoever. Each controller is a class that does not extend anything. Instead you can inject other components into it (using dependency-injection). For example:
#Controller
#RequestMapping("/user")
public class UserController {
#Inject
private UserService service;
#RequestMapping("/register")
public String register(User user) {..}
}
#Controller
#RequestMapping("/orders")
public class OrderController {
#Inject
private UserController userController
}
(Although it is not a common practice to inject controllers into other controllers, you can inject any object)

web2py - controllers are functions
web.py
puremvc - controllers are Commands
camping - odd, replaces internal controllers
limonade - procedural

Django has decided to use different terms for the MVC pattern. In django-speak "view" is what most people call controller. a django view is just a function taking a request instance and returning a response instance. Roughly it looks like this:
from django.http import HttpResponse, Http404
import datetime
def current_datetime(request):
if request.method != 'GET':
raise Http404
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)

JSF & Spring MVC
An easy tutorial for JSF: www.coreservlets.com/JSF-Tutorial/jsf2/index.html#Annotations
A basic example from SpringSource: http://src.springframework.org/svn/spring-samples/mvc-basic/trunk
Q: Why JSF
A:
You can perform your action at SimpleController#doSomething
#ManagedBean
public class SimpleController {
public String doSomething() {
...
}
}
And SimpleController does not extend any controller, #ManagedBean helps to make it look like a controller.
Q: Why Spring MVC
A:
You can perform your action at "..../doSomething"
#Controller
public class SimpleController {
#RequestMapping("/doSomething")
public String doSomething() {
...
}
}
SimpleController does not extend any controller.
#Controller helps to make the class a controller
#RequestMapping bind its url to "/doSomething"
[sorry for bold url, i can only post maximum one url in an answer as a newbie :-S]

Struts 2 also lets you do this. All the actions are simple java beans.

Related

Can we have multiple controllers in a Spring MVC application?

Can we have multiple controllers in a Spring MVC application? If yes, can someone provide a working example to support this concept?
Of course you can. There's not much to provide:
#RestController
public class UserController {
#GetMapping("/users")
// method etc.
}
#RestController
public class AccountController{
#GetMapping("/accounts")
// method etc.
}

Define front end controller for specific application in project

I created a front end controller within a project containing multiple (REST) applications. The issue is now that, the controller gets applied for all applications I try to access through the browser. I would like to ask whether the is a configuration or annotation to define for which application the controller should get applied.
This is the code of the controller:
#Controller
public class FrontendController {
#RequestMapping(value = "/")
public String index() {
return "index";
}
}
In the same package the application which serves the front end sources is implemented:
#SpringBootApplication
public class WebServer {
public static void main(String[] args) {
// Tell server to look for web-server.properties or web-server.yml
System.setProperty("spring.config.name", "web-server");
SpringApplication.run(com.studienarbeit.chaoscenter.services.departments.DepartmentsServer.class, args);
}
}
The other applications are in different packages and yet they still serve the front end sources. There are no other controllers in the project and the other applications use Spring Data REST repositories.
Note: Each application runs on its own port.
Note 2: I tried the approach using a profile for the controller:
#Profile("web-server")
Since I work with IntelliJ, I set the active profile to web-server and add the following flag in the VM Options for the specific application:
-Dspring.profiles.active=web-server
Somehow still my other applications access the front end controller. Maybe I did miss something?
Note 3: The other application implementations look basically exactly like the WebServer application and they use Spring Data REST repositories which look like this:
public interface EmployeeRepository extends CrudRepository<Employee, Long> {
}
Use specific RequestMapping values for each of your controller classes like :
#Controller
#RequestMapping("/controller1")
public class FrontendController {
#RequestMapping(value = "/")
public String index() {
return "index";
}
}
So you would consume this endpoint with the url http://localhost:8080/controller1
Also, if you're not going to use Mvc Views and this will be only a Rest Controller, use #RestController insted #Controller.
#RestController
#RequestMapping("/controller1")
public class FrontendController
It's a combination of #Controller and #ResponseBody annotations. Detailed information could be found at here.

Controller or RestController

i'm new to jEE, and this is my first jEE code using spring. The code bellow is working fine. He just print the string index when i go to my localhost; and otherwise he print handling error.
My question is: Why this code isn't working anymore if I use #Controller instead of #RestController
I can't find any simple explanation in the docs from spring and I was hoping someone could explain this.
I have the feelings that a controller alone can't work without something like thymeleaf (I know if I were using thymeleaf the string index would be replaced by the index page from the ressources folder) where a RestController might be returning data as xml or json or something else.
Thanks
#RestController
public class HelloController implements ErrorController {
#RequestMapping("/")
public String index() {
return "index";
}
#RequestMapping("/error")
public String error() {
return "gestion erreur";
}
#Override
public String getErrorPath() {
return "/error";
}
}
The job of #Controller is to create a Map of model object and find a view but #RestController simply return the object and object data is directly written into HTTP response as JSON or XML.
The #Controller is a common annotation which is used to mark a class as Spring MVC Controller while #RestController is a special controller used in RESTFul web services and the equivalent of #Controller + #ResponseBody.
If you want the same functionality of #RestController without using it you can use #Controller and #ResponseBody.
#Controller
public class HelloController{
#RequestMapping("/")
#ResponseBody
public String index() {
return "index";
}
}

Spring MVC: Inheriting controllers

Within my web application I have a tool for generating PDF/XLS reports. These "reporters" inherit from a basic controller and they just describe the reporting functionality, something like:
public abstract class Reporter {
getPath() {
return "/reporter/" + getClass().getSimpleName().replace("Reporter", "").toLowerCase() + ".{pdf|xls}";
}
handleRequest() {
// prepare the data
generateReport(...)
// do something with it
// then report pdf or excel
}
}
#Controller
public class DailyReporter extends Reporter {
#Override
void generateReport(...) {}
}
#Controller
public class AverageReporter extends Reporter {
#Override
void generateReport(...) {}
}
In this way I can just describe the data for each Reporter.
Using Spring MVC, the getPath() method is actually part of the Annotation, but using getClass().getSimpleName().toLowerCase() in the annotation is not possible as it needs to be "Compile time constant". Is there a way to do this with Spring MVC?
Don't use inheritance. Use composition/delegation.
Have a single controller, mapped to /reporter/{type}.{pdf|xls}. Define an interface Reporter, and one spring bean implementing that interface per type of report. Inject a List<Reporter> in your controller. And for each request, find the reporter responsible for the type passed in the URL, and call it.

How to Generify REST Controller in Spring MVC to Remove Duplication

I have a design issue I cannot for the life of me figure out.
Good code has no duplication. I have generified my DAO so all basic crud operations are inherited
I'm trying to do the same with Spring MVC with Annotated Controllers.
I found this question but no answer is there: How to Remove Duplication from Spring 3 MVC Standard and Ajax Request Controllers and Views
If I have something like the below example, assuming I refactor to use AbstractBaseService and BaseModel (I did this but don't have the code), how can I put the annotation info into something like a GenericAbstractBaseController or BaseController interface? I've tried (don't have the code here) but the problem is that Annotations ARE NOT inherited and CANNOT be added at run time.
I see that javassist can be used for bytecode modification so that I actually CAN add annotations after compiling to keep the code clean but this appears to be overly complex.
I sent a note to a mentor and he suggested using AOP with naming convention to weave advice or reflection to identify the annotations from the inherited class but I'm not certain how I could actually give this info to spring given that I cannot actually add annotations at runtime. I think I'm missing some critical key here that someone will come and drop - he only sent me back a couple lines.
Here is the code - how can I remove the duplicate crud logic.
#Controller
#RequestMapping("/users")
public class UserController {
#Autowired
UserService userService;
#RequestMapping(value="/", method = RequestMethod.GET)
public #ResponseBody List<User> doGetIndex(ModelMap model) {
return userService.listPage(0, 10);
}
#RequestMapping(value="/{name}", method = RequestMethod.GET)
public #ResponseBody User doGet(#PathVariable String name, ModelMap model) {
return userService.getByUsername(name);
}
//post
//put
//delete
I don't quite understand what do you mean by "annotations are not inherited", but as far as I remember the following approach should work:
public class AbstractController<T> {
#RequestMapping(value="", method = RequestMethod.GET)
public #ResponseBody List<User> doGetIndex(ModelMap model) { ... }
#RequestMapping(value="{name}", method = RequestMethod.GET)
public #ResponseBody T doGet(#PathVariable String name, ModelMap model) { ... }
}
#Controller
#RequestMapping("/users")
public class UserController extends AbstractController<User> { ... }

Resources