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.
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";
}
}
Im trying to have java respond to a GET request from Postman. When I use Postman to send a GET request to localhost:8080/chat this is the response (I had expected to get an empty list returned as there is no data present yet:
{
"timestamp": "2018-04-02T20:00:26.413+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/chat"
}
I have 2 packages in my application. They are com.dogo and com.dogochat.chat. The file in com.dogo is DogoApplication.java. This is the code:
package com.dogo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class DogoApplication {
public static void main(String[] args) {
SpringApplication.run(DogoApplication.class, args);
}
}
The second package is called com.dogochat.chat. There are 3 files (2 classes and 1 interface). The file names are Message.java, MessageController.java, and MessageRepository.java.
This is the code in Message.java:
package com.dogochat.chat;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="message")
public class Message {
#Id
#GeneratedValue
private Integer id;
private String name;
private String content;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
This is the code in MessageController.java:
package com.dogochat.chat;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
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("/chat")
public class MessageController {
#Autowired
MessageRepository dao;
#GetMapping("/get")
public List<Message> getMessages(){
List<Message> foundMessages = dao.findAll();
return foundMessages;
}
#PostMapping("/post")
public ResponseEntity<Message> postMessage(#RequestBody Message message)
{
// saving to DB using instance of the repo interface
Message createdMessage = dao.save(message);
// RespEntity crafts response to include correct status codes.
return ResponseEntity.ok(createdMessage);
}
}
This is the code in MessageRepository.java (although I dont think this is needed for this small test)
package com.dogochat.chat;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MessageRepository extends JpaRepository<Message, Integer>{
}
Any help/suggestions are greatly appreciated.
Thanks.
I know I am pretty late for the response, but better late than never.
This is a very common mistake for new Spring boot developers and I have also faced this issue several times.
The reason for this is the package under which you have your main() method.
In your case your MessageController, Message and your MessageRepository is under the package com.dogochat.chat, but then your main() method is under com.dogo which is completely a different package.
#SpringBootApplication internally runs #ComponentScan and if parent package and child packages are different, it cannot run and scan and throws the above error.
To avoid this confusion, follow this package structure.
Hope this helps. Happy coding !
Check to see if your #SpringBootApplication class is on top of all your packages or at least in the same package. It seems like your URL path is not visible.
Also, in your PostMan, you have to configure your headers the content-type=application/json.
For a more readable code (just my point of view), you should have something like this :
package com.dogochat.chat;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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("/chat")
public class MessageController {
#Autowired
MessageRepository dao;
#GetMapping("/get")
public List<Message> getMessages(){
List<Message> foundMessages = dao.findAll();
return foundMessages;
}
#PostMapping("/post")
public ResponseEntity<Message> postMessage(#RequestBody Message message)
{
// saving to DB using instance of the repo interface
Message createdMessage = dao.save(message);
// RespEntity crafts response to include correct status codes.
return ResponseEntity.ok(createdMessage);
}
}
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?
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;
}
}