How to call a service from a controller - spring

I am trying to call the following service from a controller:
#Service
class MyMailService {
private final SendGrid sendGrid;
#Inject
public SendGridMailService(SendGrid sendGrid) {
this.sendGrid = sendGrid;
}
void sendMail() {
Request request = new Request();
Response response = this.sendGrid.api(request);
}
}
And my controller:
# controller
public String index(Model model) {
MyMailService.sendMail() // how to do this properly?
return "register";
}
What would be the correct way to call this from a controller? Basically, I'm trying to "autoconfigure" sendgrid, so I don't have to initialize the SendGrid object with the API key whenever I call the MyMailService class.

As suggested by others, I do think too you need to spend more time learning Java & Spring basics. But to answer your question, you auto-wire/inject your service singleton object in the controller to use it:
#Controller
public class ControllerA
{
.
.
.
#Autowired
private MyMailService mymailService; //singleton object instance injected to be used/shared by all controllers
public String index(Model model) {
mymailService.sendMail()
return "register";
}
.
.
.
}

You can call your service in below ways
1) Simply adding #Autowired to your class type
#Autowired
MyMailService myMailService;
2) Using Constructor Injection as below,
MyMailService myMailService;
#Autowired
public WebController(MyMailService myMailService) {
this.myMailService = myMailService;
}
- here i assumed my Controller name is WebController
3) Using Setter Injection as below,
MyMailService myMailService;
#Autowired
public void setMyMailService(MyMailService myMailService) {
this.myMailService = myMailService;
}
and finally in your controller you can call your service class methods as below,
myMailService.sendMail();
Note:
Follow naming convention.

Related

Calling other request mapping from rest controller

I am trying to call other rest controller from reqest mapping .
#RestController
class MyController{
#Autowired
OtherController other
#RequestMapping(/{token}/add)
public MyDto add(String token){
String[] tokens = token.split("\\.");
I want to call process input from method from Other controller and send token[1] item as path param
}
}
#RestController
public class OtherController{
#RequestMapping(/token/process)
public processInput(#PathVariable token)
{
}
}
How to send spited token to other param as path param. Could you please advice the calling strategy
It is possible to call another controller. You can simply inject your Controller into the class you would like to make that call in. This allows you to use the OtherController controller as if it was a Service component.
#RestController
class MyController {
private final OtherController otherController;
public MyController(#Autowired OtherController otherController) {
this.otherController = otherController;
}
#RequestMapping(/{token}/add)
public MyDto add(String token){
InputDto input=new InputDto();
otherController.processInput(input);
}
}

#Value annotation not working in constructor

I have an issue where Spring #Value annotation not working in the constructor.
I have this Email class that is reading some email related configuration.
In the constructor, if I put a break-point the values are empty
But if I call the sendEmail method, there are values.
The other class:
#Autowired
Email sender;
Email class:
#Component
public class Email{
#Value("${TO_EMAIL}")
private String toEmail;
public Email() {
// Here toEmail is null
}
public void sendEmail(String subject, String body) {
// Here toEmail has value
}
}
As far I remember, the value injection occurs after the constructor call.
Try to change your constructor to this:
public Email(#Value("${TO_EMAIL}") String toEmail) {
this.toEmail = toEmail;
}
The value injection occures after the constructor call, to solve this in your case, you can leave the constructor empty. And add a method annotated with "#PostConstructor".
This way, the empty constructor will be called, then the values will be injected, then the #PostConstructor method will be called.
I encountered similar problems when I work with ApplicationRunner
public class AppStartupRunner implements ApplicationRunner {
#Autowired
private Environment myEnv; //not work
#value(${xxx.xxx})
private String myValue //not work
#Autowired
public AppStartupRunner(Environment env) {
System.out.println(myEnv); //null
System.out.println(myValue); //null
}
}
After I changed to the below codes, it works perfectly
#Autowired
public AppStartupRunner(Environment env) {
env.getProperty("key") //works!
}

DirectConsumerNotAvailableException when defining camel routes in springboot

I am trying to create a simple spring boot app which takes list of routes and process it parallelly in routebuilder. I am using proceduretemplate to call my routes by defining my startroute: direct start. When i hit i am getting org.apache.camel.component.direct.DirectConsumerNotAvailableException: No consumers available on endpoint: Endpoint[direct://start].Exchange.[]. I am unable to figure out the issue here.below is my code.
TestController.java
#RestController
#RequestMapping(value = "/service")
#Component
public class TestController {
#EndpointInject(uri = "direct:start")
private ProducerTemplate template;
#RequestMapping(value = "/test",method =RequestMethod.GET)
public void getAccountDetails(){
ArrayList<String> callList = new ArrayList<String>();
callList.add("direct:phone");
callList.add("direct:sms");
callList.add("direct:email");
template.sendBody(callList);
}
CamelRoute.java
#Component
public class CamelRoute extends RouteBuilder {
final String BASE_ROUTE = "direct:start";
public void configure() throws Exception {
from(BASE_ROUTE).recipientList(body()).setParallelProcessing(true);
from("direct:phone").log("customer call made");
from("direct:sms").log("phone call made");
from("direct:email").log("email call made");
}
version
camel-spring-boot-starter', version: '2.17.0'
Thanks in advance.

calling a method by class level annotated with #RequestMapping that includes an autowired class

I am trying to call a method that is annotated with #RequestMapping(signIn) through a class level (from method: authentication) like so:
#RequestMapping(value = /authenticate, method = RequestMethod.POST)
public #ResponseBody Response authentication(HttpServletRequest request)
{
UserController user = new UserController();
return user.signIn(request, null);
}
and my controller looks like:
#Autowired
private UserManager userManager;
#RequestMapping(value = /signin, method = RequestMethod.POST)
public #ResponseBody Response signIn(HttpServletRequest request) {
JsonObject json = Misc.parseJson(request);
String lang = Misc.getLang(request);
user.setEmail(Misc.getEmail(json));
user.setPassword(Misc.getEncryptedPassword(json));
return ResponseUtils.success(userManager.auth(user, lang));
}
user manager is annotated with #component:
#Component
public class UserManager {
public User auth(User user, String lang) {
....
return user;
}
}
Problem is when I call the method "signIn" and just new-up a UserController instance through "/authenticate" mapping, the UserManager becomes NULL. So now I'm assuming that autowiring doesn't work when it's done this way.
Is there any other way to call the signIn method? I would hate to copy paste an already existing code to another class just to get this to work...
Autowiering only works in spring managed bean. If you create a class with new keyword, it is not a spring managed bean and autowiering would not work.
You can try to autowire the class which contains the method which is annotated or better put the code in a service class which can be used by both methods.
It's not problem with #Autowired .There are two type of Annotation
firstly method base annotation and field level annotation. You just used field level annotation.Check your import class with "org.springframework.beans.factory.annotation.Autowired" or it can be problem with initiation of "UserManager"
I don't know why you not moving logic into separate Service classs, but try this:
UserController.java
public UserController(UserManager userManager) {
this.userManager = userManager;
}
and then inside controller where authentication resource method is located:
#Autowired UserManager userManager;
#RequestMapping(value = /authenticate, method = RequestMethod.POST)
public #ResponseBody Response authentication(HttpServletRequest request) {
UserController user = new UserController(userManager);
return user.signIn(request);
}
So in the end I just separated the logic instead. Though one solution that I tried and I could have used was to just add another mapping to the signIn method instead of adding a new method in the other class since the logic was similar. Still I opted for a separate logic instead since there were a lot of unnecessary code in the signIn method for my purpose.

Dependency injection in Spring MVC?

I am trying to use dependency injection in my Spring MVC web application. I have a function like this in my controller
#RequestMapping(value = "/stockgoogle/", method = RequestMethod.GET)
public #ResponseBody Stock stockGoogle(Locale locale, Model model) {
StockDaoImpl si = new StockDaoImpl();
//al=s.listCurrent(id);
Stock s=si.listGoogle();
System.out.println("reached here");
model.addAttribute("s", s );
return s;
}
I want to dependency inject StockDaoImpl. Can you please tell me how I can do this. I have been trying to read but most of the explainations are very complex. Should I use #Autowired ? Where should I put it? Can you please help.
You can inject it through the Controller's constructor
class YourController{
private final StockDao dao;
#Autowired
public YourController(StockDao dao){
this.dao = dao;
}
}
And now StockDaoImpl has to be defined as a Bean of course,
#Bean
public StockDao stockDao(){
return new StockDaoImpl();
}
Another way for doing it would be defining StockDaoImpl as a Component
Add below config in Spring config file(for example root-context.xml)
then in your controller, you like below code
class TestController{
#Autowired
private StockDao stockDao;
}
With spring-4 you can directly inject in given way :
#Autowired
private StockDao stockDao;
public #ResponseBody Stock stockGoogle(Locale locale, Model model) {
//al=s.listCurrent(id);
Stock s = stockDao.listGoogle();
System.out.println("reached here");
model.addAttribute("s", s );
return s;
}
Here
StockDao will contain method signature
StockDaoImpl implements StockDao and definition of methods
Autowired will inject that Dao and you can use its method.

Resources