I have this class, which is part of a SpringBoot Application
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.springboot.tutorial.upwork.service.WelcomeService;
#RestController
public class WelcomeController {
#Autowired
private WelcomeService service;
// http://localhost:7777/welcome
#RequestMapping("/welcome")
public String welcome() {
return service.retrieveWelcomeMessage();
}
// http://localhost:7777/welcome/bla
#RequestMapping("/welcome/{msg}")
public String welcome(#PathVariable("msg") String message) {
return service.retrieveWelcomeMessage(message);
}
}
Now i need to add a variable to hold some data, which will be available to class methods. How can i do it since an instance of this class is created by Spring?
Related
I'm working with a project that has the back in Java deployed at Heroku and the front in Angular dpeloyed at Firebase. Data base is in CleverCloud.
I'm having problems with bringing data to the front from the data base.
PERSON TABLE (WORKS JUST FINE):
CONTROLLER (JAVA):
package com.portfoliocardone.portfoliocardone.Controller;
import com.portfoliocardone.portfoliocardone.Entity.Person;
import com.portfoliocardone.portfoliocardone.Interface.IPersonService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
#RestController
#CrossOrigin(origins = "https://portfoliocardone.web.app")
public class PersonController {
#Autowired IPersonService ipersonService;
#GetMapping("/person/get")
public List<Person> getPerson(){
return ipersonService.getPerson();
}
#PostMapping("/person/new")
public String createPerson(#RequestBody Person person){
ipersonService.savePerson(person);
return "The person was created correctly";
}
#DeleteMapping("/person/delete/{id}")
public String deletePerson(#PathVariable Long id){
ipersonService.deletePerson(id);
return "The person was deleted correctly";
}
//URL:PORT/person/edit/id/name & lastname & img & about me
#PutMapping("/person/edit/{id}")
public Person editPerson(#PathVariable Long id,
#RequestParam("name") String newName,
#RequestParam("lastname") String newLastname,
#RequestParam("img") String newImg,
#RequestParam("aboutme") String newAboutme){
Person person = ipersonService.findPerson(id);
person.setName(newName);
person.setLastname(newLastname);
person.setImg(newImg);
person.setAboutme(newAboutme);
ipersonService.savePerson(person);
return person;
}
#GetMapping("/person/find/profile")
public Person findPerson(){
return ipersonService.findPerson((long)1);
}
}
SERVICE ANGULAR PROJECT:
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
import { person } from '../model/person.model';
#Injectable({
providedIn: 'root'
})
export class PersonService {
URL = 'https://portfoliocardone.herokuapp.com/person/';
constructor(private http:HttpClient) { }
public getPerson(): Observable<person>{
return this.http.get<person>(this.URL+'find/profile');
}
}
After I bring the data to the component by putting {{person.name}}, {{person.lastname}}, {{person.aboutme}} in the html file. I left the image empty and it works just fine.
HERE IS THE PROBLEM WITH THE OTHER TABLE:
CONTROLLER (JAVA):
package com.portfoliocardone.portfoliocardone.Controller;
import com.portfoliocardone.portfoliocardone.Entity.Experience;
import com.portfoliocardone.portfoliocardone.Interface.IExperienceService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
#RestController
#CrossOrigin(origins = "https://portfoliocardone.web.app")
public class ExperienceController {
#Autowired IExperienceService iexperienceService;
#GetMapping("/experience/get")
public List<Experience> getExperience(){
return iexperienceService.getExperience();
}
#PostMapping("/experience/new")
public String createExperience(#RequestBody Experience experience){
iexperienceService.saveExperience(experience);
return "The experience was created correctly";
}
#DeleteMapping("/experience/delete/{id}")
public String deleteExperience(#PathVariable Long id){
iexperienceService.deleteExperience(id);
return "The experience was deleted correctly";
}
//URL:PORT/experience/edit/id/title & time & location & description
#PutMapping("/experience/edit/{id}")
public Experience editExperience(#PathVariable Long id,
#RequestParam("title") String newTitle,
#RequestParam("time") String newTime,
#RequestParam("location") String newLocation,
#RequestParam("description") String newDescription){
Experience experience = iexperienceService.findExperience(id);
experience.setTitle(newTitle);
experience.setTime(newTime);
experience.setLocation(newLocation);
experience.setDescription(newDescription);
iexperienceService.saveExperience(experience);
return experience;
}
#GetMapping("/experience/find/profile/{id}")
public Experience findExperience(#PathVariable("id") Long id){
return iexperienceService.findExperience((long)id);
}
}
ANGULAR SERVICE
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
import { experience } from '../model/experience.model';
#Injectable({
providedIn: 'root'
})
export class ExperienceService {
URL = 'https://portfoliocardone.herokuapp.com/experience/';
constructor(private http:HttpClient) { }
public getExperience(): Observable<experience>{
return this.http.get<experience>(this.URL+'find/profile/{id}');
}
}
ERRORS I GET IN CONSOLE:
headers: An, status: 400, statusText: 'OK', url:...
Does someone know how to be able to bring the data from this second table? Thanks!
I have a HTML page that is launched from a java controller after a post and I want to attach a query string value in the url ex: (localhost:8000/gdata?id=11). Can this be done? Here is my controller code:
package com.sa.example;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
//import org.springframework.web.bind.annotation.RequestParam;
import com.sentinel.advisor.GData;
import com.sentinel.advisor.GDataJdbcRepository;
#Controller
public class GDataController {
#Autowired
GDataJdbcRepository repository;
#GetMapping("/gdata")
public String gDataForm(Model model) {
return "gData";
}
#PostMapping("/gdata")
public String gDataSubmit(#ModelAttribute GData gData) {
String returnString = repository.insert(gData);
//returnString should be returned in the url as a query string
return "result";
}
}
You can use a redirect (it is best practice to redirect after post regardless see - https://en.wikipedia.org/wiki/Post/Redirect/Get.
Spring's redirect view:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/view/RedirectView.html
Something like:
#Controller
public class GDataController {
#Autowired
GDataJdbcRepository repository;
#GetMapping("/gdata")
public String gDataForm(Model model) {
return "gData";
}
#PostMapping("/gdata")
public RedirectView gDataSubmit(#ModelAttribute GData gData) {
String returnString = repository.insert(gData);
return new RedirectView("/sucess?returnString=" + returnString, true);
}
#GetMapping("/success")
public String getResultPage(#RequestParam("returnString")String returnString){
return "result";
}
}
I have an application with two packages. In the first package, I have 2 controllers. The first controller is called APIController.java which displays a view. This is the code of the controller:
package com.dogo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
#RequestMapping()
public class APIController {
#RequestMapping("/api")
public String apiChat() {
return "apiChat.html";
}
}
The second controller is called HomeController.java which I use to display the index.html page. This is the code:
package com.dogo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class HomeController {
#RequestMapping("/")
public String index() {
return "index.html";
}
}
The second package also contains a controller called MessageController.java. This is used to update a dao database based on the parameters passed in the url. This is the code for this controller:
package com.dogo.chat;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping()
public class MessageController {
#Autowired
MessageRepository dao;
#GetMapping("/chat")
public List<Message> getMessages(){
List<Message> foundMessages = dao.findAll();
return foundMessages;
}
#PostMapping("/chat")
public ResponseEntity<Message> postMessage(#RequestBody Message message)
{
// Saving to DB using an instance of the repo Interface.
Message createdMessage = dao.save(message);
// RespEntity crafts response to include correct status codes.
return ResponseEntity.ok(createdMessage);
}
#GetMapping("/chat/{id}")
public ResponseEntity<Message> getMessage(#PathVariable(value="id")
Integer id){
Message foundMessage = dao.findOne(id);
if(foundMessage == null) {
return ResponseEntity.notFound().header("Message","Nothing found with that id").build();
}
return ResponseEntity.ok(foundMessage);
}
#DeleteMapping("/message/{id}")
public ResponseEntity<Message> deleteMessage(#PathVariable(value="id") Integer id){
Message foundMessage = dao.findOne(id);
if(foundMessage == null) {
return ResponseEntity.notFound().header("Message","Nothing found with that id").build();
}else {
dao.delete(foundMessage);
}
return ResponseEntity.ok().build();
}
}
When I type http://localhost:8080/api into my browser, the apiChat.html page is displayed. When I change the #RequestMapping() in APIController.java to #RequestMapping("/api") and I type http://localhost:8080/api/api I get a 404 error. I had expected the apiChat.html page to be displayed. What am I missing? Thank you.
Trying to simply validate a field of my bean and instead of doing it manually wanted to check out Spring Validation, but didn't have much luck as of now.
In short:
Validation with #Valid annotation seems to never be called when I call a method of my #RestController
My code:
pom.xml (for the validation part)
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
Spring is version 4.1.1
Validator
package mypackage;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
public class UtenteValidator implements Validator{
public UtenteValidator() {
// TODO Auto-generated constructor stub
}
#Override
public boolean supports(Class<?> clazz) {
return UtenteLite.class.equals(clazz);
}
//validation test
#Override
public void validate(Object target, Errors errors) {
UtenteLite user = (UtenteLite) target;
if(user.getName != "foo") {
errors.rejectValue("name", "name not correct");
}
}
}
Controller
package myPackage;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/users")
public class UsersController {
public UsersController() {
}
//tried to put #InitBinder, but no luck
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new UtenteValidator());
}
#ResponseBody
#RequestMapping(value="", method=RequestMethod.PUT)
public <T> ResponseEntity<T> aggiornaUtente(#RequestBody #Valid UtenteLite utente, BindingResult result)
{
ResponseEntity<T> responseEntity=null;
return responseEntity;
}
}
Te BindingResult result object shows always zero errors and the validate, supports or initBinder methods are never called.
Found this tutorial that reads:
When #InitBinder methods get called?
The #InitBinder annotated methods
will get called on each HTTP request if we don't specify the 'value'
element of this annotation.
WebDataBinder argument is specific to a model attribute. That means
each time a model attribute is created by Spring this method will get
called with a new instance of WebDataBinder.
So I tried to change my controller method to this adding a #ModelAttribute and NOW the validation code gets called BUT the requestBody object (the "utente" object) is empty, so validation always fails because the fields are all nulls:
#ResponseBody
#RequestMapping(value="", method=RequestMethod.PUT)
public <T> ResponseEntity<T> aggiornaUtente(#RequestBody #Valid #ModelAttribute("utente") UtenteLite utente, BindingResult result)
{
...
}
The utente method parameter is passed with a JSON as the body of the request.
Ok,
after several tries I succeded in producing a working solution just by adding the hibernate-validation artifact reference in my pom.xml.
I wrongly supposed the hibernate-validator was mandatory only if I was usig validation annotations on the beans properties (like #NotNull, #Pattern, etc..)
So only by adding this snippet I was able to solve my problem (hope this will spare a few hours of work to someone else):
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.3.Final</version>
</dependency>
The complete code now is:
Validator
package mypackage;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
public class UtenteValidator implements Validator{
public UtenteValidator() {
// TODO Auto-generated constructor stub
}
#Override
public boolean supports(Class<?> clazz) {
return UtenteLite.class.equals(clazz);
}
//validation test
#Override
public void validate(Object target, Errors errors) {
UtenteLite user = (UtenteLite) target;
if(user.getName != "foo") {
errors.rejectValue("name", "name not correct");
}
}
}
Controller
package myPackage;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/users")
public class UsersController {
public UsersController() {
}
//tried to put #InitBinder, but no luck
#InitBinder
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new UtenteValidator());
}
#ResponseBody
#RequestMapping(value="", method=RequestMethod.PUT)
public <T> ResponseEntity<T> aggiornaUtente(#RequestBody #Valid UtenteLite utente)
{
ResponseEntity<T> responseEntity=null;
return responseEntity;
}
}
I have a simple PersonController class that provides save() method to persist the object from http post request.
package org.rw.controller;
import java.sql.Timestamp;
import java.util.List;
import org.rw.entity.Person;
import org.rw.service.PersonService;
import org.rw.spring.propertyeditor.TimestampPropertyEditor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping(value="/person")
public class PersonController {
private static final Logger logger = LoggerFactory.getLogger(PersonController.class);
#Autowired
private PersonService personService;
#Autowired
TimestampPropertyEditor timestampPropertyEditor;
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Timestamp.class, "dob", timestampPropertyEditor);
}
#RequestMapping(value="/save", method=RequestMethod.POST)
public String save(Model model, Person person) {
Long personId = personService.save(person);
return "redirect:view/" + personId;
}
}
As the save() method returns as return "redirect:view/" + personId;. It will be diffrerent for every request. it may be like "view/5" or "view/6" depending on the id of the object that has been persisted.
Then i have a simple class to test the above controller with spring mocking.
package org.rw.controller;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Test;
import org.rw.service.UserService;
import org.rw.test.SpringControllerTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
public class PersonControllerTest extends SpringControllerTest {
#Autowired
private UserService userService;
#Test
public void add() throws Exception {
mockMvc.perform(get("/person/add", new Object[0])).andExpect(status().isOk());
}
#Test
public void save() throws Exception {
UserDetails userDetails = userService.findByUsername("anil");
Authentication authToken = new UsernamePasswordAuthenticationToken (userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authToken);
mockMvc.perform(
post("/person/save", new Object[0])
.param("firstName", "JunitFN")
.param("lastName", "JunitLN")
.param("gender", "M")
.param("dob", "11/02/1989")
).andExpect(
redirectedUrl("view")
);
}
}
now here i have a problem that redirectedUrl("view") is rejecting value "view/5". I have tried redirectedUrl("view*") and redirectedUrl("view/*") but its not working.
Edit :
Here I have got a workaround as per below
MvcResult result = mockMvc.perform(
post("/person/save", new Object[0])
.param("firstName", "JunitFN")
.param("lastName", "JunitLN")
.param("gender", "MALE")
.param("dob", "11/02/1989")
).andExpect(
//redirectedUrl("view")
status().isMovedTemporarily()
).andReturn();
MockHttpServletResponse response = result.getResponse();
String location = response.getHeader("Location");
Pattern pattern = Pattern.compile("\\Aview/[0-9]+\\z");
assertTrue(pattern.matcher(location).find());
but still i am looking for the proper way.
update:
I have posted the same issue on spring jira here :
Since spring 4.0 you can use redirectedUrlPattern as pointed by Paulius Matulionis
As of spring 3.x this is not supported out of the box but you can easily add you custom result matcher
private static ResultMatcher redirectedUrlPattern(final String expectedUrlPattern) {
return new ResultMatcher() {
public void match(MvcResult result) {
Pattern pattern = Pattern.compile("\\A" + expectedUrlPattern + "\\z");
assertTrue(pattern.matcher(result.getResponse().getRedirectedUrl()).find());
}
};
}
And use it like build-in matcher
mockMvc.perform(
post("/person/save", new Object[0])
.param("firstName", "JunitFN")
.param("lastName", "JunitLN")
.param("gender", "M")
.param("dob", "11/02/1989")
).andExpect(
redirectedUrlPattern("view/[0-9]+")
);
Since 4.0 it is available in Spring itself.
Please check here.