Can we extend the controller in Spring MVC? How should we handle the #RequestMapping in the extended controller class? If anyone has any example please share. Thanks.
If BaseController's annotation cannot be removed, then you can use Adapter Pattern to obtain the inheritance.
#Controller
public class NewController {
// Autowired fields
BaseController base;
protected x toExtend() {
base.toExtend();
//new stuff
}
}
In usual cases, either BaseController does not have #Controller annotation, hence common controller methods can be put inside BaseController to be extended by actual controllers
Related
I am writing a small CRUD in Spring and Java. And I want to use a separate file for writing logic, this is very convenient for me, I did this when developing with NestJS. I have a few questions, is it correct to do this in Spring, or should I do everything inside a function in the controller. And if I write logic in a separate file, I should mark the logic class as #Component and the functions inside it as #Bean, right? I am new to Spring and as I understand it, I have to do this in order for the application to work correctly and my functions to be in the application context.
AuthLogic.java
#Component
public class AuthLogic {
#Bean
public void register() {
// code ...
}
}
AuthController.java
#RestController
public class AuthController {
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
you can mark your logic class with #Service and use that for example you can make a AuthService and use it like
#Service
public class AuthService{
public returnType login(){
//Logic
}
}
and use this like
#RestController
public class AuthController {
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
authService.login();
}
}
You can write your business logic in a new separate file at service layer.
Suppose you name it as AuthService and you mark it with annotation #Service.
#Service
public class AuthService{
}
You can then Autowire it in your controller class.
#RestController
public class AuthController {
#Autowired
AuthService authService;
#RequestMapping(value = "/register", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public void register(#Valid #RequestBody UserDTO newUser) {
// here I call the register function from AuthLogic
}
}
Using separate files, or classes more importantly, is very recommended in Spring, and I assume most other languages.
The #Bean annotation on AuthLogic.java is unneeded and I think may cause startup or compilation errors.
I would change the name of AuthLogic to AuthLogicImpl, create an interface named AuthLogic with the method signature void register(), and have AuthLogicImpl implement AuthLogic. Then you can create a constructor for AuthController which accepts and AuthLogic parameter and sets it to a private field (note using the interface not the implementation in the constructor).
At the core of Spring is the IoC container. This container holds "beans" that can be injected or autowired into other beans. These beans are an instance of their class and can be used by other beans. Remember Spring uses the singleton pattern, so your beans should be stateless. This allows Spring to handle the application startup for you, so you don't need to write a ton of code creating all the different services/classes and wiring them together, it's all automagically done for you.
There are two key annoitations that you appear to be confused about:
#Component Putting this above a class will create an instance of that class (a bean) and put it into the IoC container. Other beans can access this by accepting the original beans interface in its constructor. So if I put #Component above my class FooImpl which implements Foo, then I can create a class, BarImpl with the constructor public BarImpl(Foo foo) {this.foo = foo} and BarImpl can use any public method of Foo (which will use FooImpl's implementation).
#Bean this is to be put on a method of a class that is annotated with #Configuration. This tells Spring that this method should be run at startup, and this method will return a bean that Spring should add to the IoC container. This is a popular way of configuring a bean that requires some parameters, such as the bean that manages the connection to a third party service or datastore, especially when that there is a little bit of logic that needs to go into creating the bean.
Note that the above is very broad, and there are some specifics if you need to dig deep into the spring framework, so there will be more clarification in the Spring documentation or you dig into some established Spring project. However it should suffice to answer the broad question of what is going on with #Component and #Bean.
There is no specific layout or code structure for Spring Boot Projects. However, there are some best practices followed by developers that will help us too. You can divide your project into layers like service layer, entity layer, and repository layer.
We use the entity layer to write all model and POJO classes. We annotate them with #Entity.
We use #Repository to indicate that this is a repository interface that is used to do some basic CRUD operations.
Sidenote:- You don't have to write #Repository for classes that implement or interfaces that extends Repository interfaces provided by Spring Boot framework.
We use #Service to say that this is the service class where your all business logic will be present.
We use the controller layer to receive HTTP requests and send back HTTP Responses or views.
You can learn and understand more from here
You can refer to this Image to understand the structure
project structure
I've wondered this for a while, but haven't been able to find anything on the topic.
Let's say I'm using Spring MVC and defining a series of Controllers.
#RestController
public abstract class AbstractController {
#Resource
private Environment env;
...
...
}
For the following, is a #RestController annotation necessary for UserController to register?
#RequestMapping(value = "/user")
public class UserController extends AbstractController {
#RequestMapping("value = "", method = RequestMethod.GET)
public ResponseEntity<User> getUser() {
...
return new ResponseEntity<>(user, HttpStatus.OK);
}
}
If you decide the annotation to be #Inherited, yes. In this example, #RestController is not defined with the #Inherited meta-annotation, so it is not applied to subclasess of AbstractController.
There are two questions here. SJuan76 has answered the first, concerning inheritance of type annotations.
The second question
is a #RestController annotation necessary for UserController to register?
is a little more involved.
Spring has a concept of meta-annotations:
Many of the annotations provided by Spring can be used as
meta-annotations in your own code. A meta-annotation is simply an
annotation that can be applied to another annotation.
[...]
Meta-annotations can also be combined to create composed annotations.
For example, the #RestController annotation from Spring MVC is
composed of #Controller and #ResponseBody.
However, the component scanning process will not generate a bean definition for abstract classes. What's more, it won't discover these meta-annotations on subtypes that aren't themselves annotated. In other words, Spring will skip over your UserController type and won't register a bean definition for it. (I'm sure it could, it just doesn't as of 4.1.7.RELEASE.)
Now, if you did annotate your type UserController with #Component to force Spring to generate a bean definition, the Spring MVC process that handles #ResponseBody would detect the #RestController annotations on the AbstractController supertype.
This is done in RequestResponseBodyMethodProcessor which uses AnnotationUtils.findAnnotation to find an annotation on the type that contains your handler method. Its javadoc states
Find a single Annotation of annotationType on the supplied Class,
traversing its interfaces, annotations, and superclasses if the
annotation is not present on the given class itself.
This method explicitly handles class-level annotations which are not
declared as inherited as well as meta-annotations and annotations on
interfaces.
Therefore, if you had
#Component
#RequestMapping(value = "/user")
public class UserController extends AbstractController {
Spring would detect and generate a bean for UserController. When handling a request to /user with your getUser handler method, Spring MVC would operate as if your class was actually annotated with #RestController (or #ResponseBody).
However, again in your case, your handler method is returning a ResponseEntity. That's not handled by the HandlerMethodReturnValueHandler for #ResponseBody, it's handled by HttpEntityMethodProcessor.
A word of caution with abstract classes meant to be supertypes of #Controller types: if you have many subtypes also meant to be beans and the abstract supertype contains #RequestMapping annotated methods, Spring MVC will fail to register your handler methods because it will consider that supertype method to be duplicated across them.
I'm new to spring, but not new to java.
I'd like to create base class for all REST services that would send notification through some messaging protocol on requests with chosen methods (POST, PUT, PACTCH) (when resource is changed basically)
So for example If I would create interface
public interface RestService<T, I> {
T get(I id);
T create();
T patch(I id);
T put(I id);
}
How can I use that in spring RestController and somehow decorate it with notifications?
All this spring #Autowire and configuration files is somewhat confusing to me, because while I'm familiar with dependency injection and used constructor dependency injection I haven't used IOC much.
I believe that the best option for you will be to use Spring AOP and put some annotation to the required methods. Please check this:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
You can use any interface or base class for any restcontroller or for any other Spring stereotype. The annotations are just clues for Spring itself to use the class as an endpoint for a rest service for example. Your class otherwise can be anything, like:
#RestController
class MyController {
#Autowired
private MyService myService; //If you use the spring sterotypes you dont need to do anything to use a bean but just to use the autowired annotation
}
#RestController
class AnyotherController extends AbstractController {...}
#RestController
class YetAnotherController extends AbstractController implements Something {}
Are all valid resources (i.e. web-components) for Spring to use.
In Spring 3.0 we use #Controller to inform Spring container to treat bean as controller .
Question How Spring decide which Base Controller class need to be extend (like MultiActionController, AbstractController etc )?
You're not extending a Controller base class when you use #Controller. Spring uses reflection to inspect the methods on a class annotated with #Controller and wire them up.
Since there are many types of controllers in Spring2.5 version, what kind of controller does Spring internally implement when #controller is used? and how does spring decide what controller to implement?
Short answer: It doesn't matter how #Controller is implemented internally.
Long answer:
First you should read the reference manual to know the API, which is primarly based on annotations. You have no AbstractController, SimpleFormController etc. Important sentence:
The #Controller annotation indicates that a particular class serves
the role of a controller. Spring does not require you to extend any
controller base class or reference the Servlet API.
You must abandon "Spring MVC 2.5 thinking" and just define beans annotated with #Controller like
#Controller
public class ClinicController {
private final Clinic clinic;
#Autowired
public ClinicController(Clinic clinic) {
this.clinic = clinic;
}
#RequestMapping("/")
public void welcomeHandler() {
}
#RequestMapping("/vets")
public ModelMap vetsHandler() {
return new ModelMap(this.clinic.getVets());
}
}
and just use them as ordinary beans (by adding to servlet.xml <bean class="com.example.ClinicController " />). It's much easier this way.