Spring Boot Hibernate Many To One not saving joinColumn result - java

I'm trying to store images in MySQL using Spring boot, I have a user entity and I want to create a Many To One relationship between my FileUpload entity.
I'm using react on the front end and the purpose of this upload service is to have profile pictures that a user can set themselves but I'd first like to get the relationship between the User and FileUpload entities correct.
The issue I have is that the joinColumn in the FileUpload table does not save the User Entities id when a user uploads an image. It just returns a null value in the foreign key field.
FileUpload.java
#Entity
#Table(name="file_upload")
public class FileUpload {
#Id
#GenericGenerator(name = "uuid", strategy = "uuid2")
#GeneratedValue(generator = "uuid")
private String id;
private String name;
private String type;
#Lob
private byte[] data;
#ManyToOne
#JoinColumn( name="user_id")
private User user;
public FileUpload() {
}
public FileUpload(String name, String type, byte[] data) {
this.name = name;
this.type = type;
this.data = data;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
FileUploadService.java
I also have a repository for this, with no custom methods inside.
#Service
public class FileUploadService {
#Autowired
private FileUploadRepository fileUploadRepository;
public FileUpload store(MultipartFile file) throws IOException {
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
FileUpload fileDB = new FileUpload(fileName, file.getContentType(), file.getBytes());
return fileUploadRepository.save(fileDB);
}
public FileUpload getFile(String id) {
return fileUploadRepository.findById(id).get();
}
public Stream<FileUpload> getAllFiles() {
return fileUploadRepository.findAll().stream();
}
}
FileUploadController.java
#Controller
#CrossOrigin()
public class FileUploadController {
#Autowired
private FileUploadService fileUploadService;
#PostMapping("/upload")
public ResponseEntity<?> uploadFile(#RequestParam("file")MultipartFile file) {
String message = "";
try {
fileUploadService.store(file);
message = "Uploaded the file successfully: " + file.getOriginalFilename();
return ResponseEntity.status(HttpStatus.OK).body(new ApiResponse(true, message));
} catch (Exception e) {
message = "Could not upload the file: " + file.getOriginalFilename() + "!";
return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(new ApiResponse(true, message));
}
}
#GetMapping("/files")
public ResponseEntity<List<?>> getListFiles() {
List<FileUploadResponse> files = fileUploadService.getAllFiles().map(dbFile -> {
String fileDownloadUri = ServletUriComponentsBuilder
.fromCurrentContextPath()
.path("/files/")
.path(dbFile.getId())
.toUriString();
return new FileUploadResponse(
dbFile.getName(),
fileDownloadUri,
dbFile.getType(),
dbFile.getData().length);
}).collect(Collectors.toList());
return ResponseEntity.status(HttpStatus.OK).body(files);
}
#GetMapping("/files/{id}")
public ResponseEntity<byte[]> getFile(#PathVariable String id) {
FileUpload fileUpload = fileUploadService.getFile(id);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileUpload.getName() + "\"")
.body(fileUpload.getData());
}
}
Postman POST request
MySQL Tables
User
FileUpload
I have the same relationship with a confirmation token entity i have to confirm a users email which does work properly with the ManyToOne relationship but this doesn't. I am using the same relationship mapping but it gives me null values as seen above.
#ManyToOne
#JoinColumn( name="user_id")
private User user;
I can upload the file fine but I want to be able to keep track of a user and their files.

You need to assign a user to this entity:
FileUpload fileDB = new FileUpload(fileName, file.getContentType(), file.getBytes());
fileDB.setUser(userThatSentImage); // you need to set user
return fileUploadRepository.save(fileDB);
How do you authenticate users? If you are using spring security, here you can find how to retrieve user from session: https://www.baeldung.com/get-user-in-spring-security

Related

How to insert a json body with multiple data to multiple tables with relationship in springboot

I have two entities: UserEntity and LoginEntity and crudrepositories for each. The entities have a relationship of OneToOne where one user will have one login account. I also created a controller and I can get all the data from the database i.e when call getalluser I get all users with their relationship to login. and when I call getAllLogins I get all logins accounts. I also managed to insert the user and the login using API each individually and it's working fine but this will omit the foreign-key user_id.
Now since am knew am stack on how to insert the user and login each respectively with their relationships through one json body
#Entity#Table(name="user_table")public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long uid;
private String fname;
private String lname;
#OneToOne( cascade = CascadeType.ALL, mappedBy = "userEntityFk")
private LoginEntity logins;
public UserEntity() {
super();
}
public Long getUid() {
return uid;
}
public void setUid(Long uid) {
this.uid = uid;
}
public String getFname() {
return fname;
}
public void setFname(String fname) {
this.fname = fname;
}
public String getLname() {
return lname;
}
public void setLname(String lname) {
this.lname = lname;
}
public LoginEntity getLogins() {
return logins;
}
public void setLogins(LoginEntity logins) {
this.logins = logins;
}
public UserEntity(Long uid, String fname, String lname, LoginEntity logins) {
super();
this.uid = uid;
this.fname = fname;
this.lname = lname;
this.logins = logins;
}
#Entity #Table(name="login_table") public class LoginEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long lid;
private String username;
private String password;
#OneToOne(cascade = CascadeType.ALL )
private UserEntity userEntityFk;
public LoginEntity() {
super();
}
public LoginEntity(Long lid, String username, String password, UserEntity userEntityFk) {
super();
this.lid = lid;
this.username = username;
this.password = password;
this.userEntityFk = userEntityFk;
}
public Long getLid() {
return lid;
}
public void setLid(Long lid) {
this.lid = lid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public UserEntity getUserEntityFk() {
return userEntityFk;
}
public void setUserEntityFk(UserEntity userEntityFk) {
this.userEntityFk = userEntityFk;
}
}
#Repository
public interface LoginRepo extends CrudRepository<LoginEntity, Integer> {
}
#Repository
public interface UserRepo extends CrudRepository<UserEntity, Integer> {
}
#RestController
#RequestMapping(path="/api")
public class MainController {
#Autowired
private UserRepo userRepository;
#Autowired
private LoginRepo loginRepository;
//===this works fine i can get all the users after insert
#GetMapping(path="/user_acc")
public #ResponseBody Iterable<UserEntity> getAllUsers() {
// This returns a JSON or XML with the users
return userRepository.findAll();
}
//================this too works fine after insert
#GetMapping(path="/login_acc")
public #ResponseBody Iterable<LoginEntity> getAlllogins() {
// This returns a JSON or XML with the users
return loginRepository.findAll();
}
//===adding single user works fine. and it returns user_id
#PostMapping("/user_acc")
public Long addNewUser(#RequestBody UserEntity userz){
UserEntity ue = userRepository.save(userz);
return ue.getUid();
}
//===this works but the foreign key not inserted and thats where my problem is
#PostMapping("/login_acc")
public LoginEntity addNewLogin(#RequestBody LoginEntity loginz){
return loginRepository.save(loginz);
}
}
class UserLogin{
UserEntity myuser;
LoginEntity mylogin;
public UserEntity getMyuser() {
return myuser;
}
public void setMyuser(UserEntity myuser) {
this.myuser = myuser;
}
public LoginEntity getMylogin() {
return mylogin;
}
public void setMylogin(LoginEntity mylogin) {
this.mylogin = mylogin;
}
}
result on post http://localhost:8080/api/login_acc. account created but no foreign key
result on post http://localhost:8080/api/login_acc. account created but no foreign key
{
"lid": 1,
"username": "admin1",
"password": "11111",
"userEntityFk": null
}
result on geting all users on get method http://localhost:8080/api/user_acc
{
"uid": 1,
"fname": "hassan",
"lname": "zahor",
"logins": null
}
what i want to post is this body below to multiple tables
{
"fname":"hassan",
"lname":"zahor",
"username": "admin5",
"password": "55555"
}
This one should works better :
{
"fname":"hassan",
"lname":"zahor",
"userEntityFk" : {
"username": "admin5",
"password": "55555"
}
}
However, you will get an error if your endpoint returns an object that contains a loop inclusion : spring will try to map it into json indefinitely.
You can correct this issue to map your result into another object before returning it from your controller, or just remove the property "logins" from UserEntity.

How to validate data in service layer in spring boot

Controller:
#RestController
#RequestMapping(path = "api/v1/users")
public class UserController {
#Autowired
UserService userService;
#PostMapping("/register")
public ResponseEntity<Map<String, String>> registerUser(#RequestBody Map<String, Object> userMap){
Map<String, String> map = new HashMap<>();
try {
String first_name = (String) userMap.get("first_name");
String last_name = (String) userMap.get("last_name");
Users user = userService.registerUser(first_name, last_name);
map.put("message:","User registered successfully");
}catch(Exception e) {
map.put("message:",e.getMessage());
return new ResponseEntity<>(map, HttpStatus.UNAUTHORIZED);
}
return new ResponseEntity<>(map, HttpStatus.OK);
}
}
Service Layer:
#Service
#Transactional
public class UserServicesImpl implements UserService{
#Autowired
UserRepository userRepository;
#Override
public Users registerUser(String first_name, String last_name) throws EtAuthException {
String username = first_name+99;
Integer userId = userRepository.create(first_namea, last_name);
return userRepository.findById(userId);
}
}
Repository:
#Repository
public class UserRepositoryImpl implements UserRepository {
private final UserRepositoryBasic userRepositoryBasic;
public UserRepositoryImpl(UserRepositoryBasic userRepositoryBasic) {
this.userRepositoryBasic = userRepositoryBasic;
}
#Override
public Integer create(String first_name, String last_name) throws EtAuthException {
try{
Users insertData = userRepositoryBasic.save(new Users(first_name, last_name));
return insertData.getId();
}catch (Exception e){
throw new EtAuthException(e.getMessage());
}
}
}
Model/Entity:
#Entity
#Table(name="users")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", updatable = false, nullable = false)
private Integer id;
#NotBlank(message="First name can not be empty")
#Column(nullable = false, length = 40)
private String first_name;
#NotBlank(message="Last name can not be empty")
#Column(nullable = false, length = 40)
private String last_name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFirst_name() {
return first_name;
}
public void setFirst_name(String first_name) {
this.first_name = first_name;
}
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public Users(String first_name, String last_name) {
this.first_name = first_name;
this.last_name = last_name;
}
public Users() {
}
}
The response I am getting is:
I want to do the validation at Service Layer but unable to do so. Validation works for my code implementation but the problem is that the validation message is shown with the package and class names which I do not want to show. I am trying to get only the validation error message if validation fail.
I tried adding #Valid annotation but unable to get the response I am looking for.
I am looking for a response below if validation fails.
"message": ["First name can not be empty","Last name can not be empty"]
Can anyone help me out with this problem. Thank you in advance.
Add a global exception handler to parse your error and return error message in the format you need.
#ExceptionHandler({ ConstraintViolationException.class })
public ResponseEntity<Object> handleConstraintViolation(
ConstraintViolationException ex, WebRequest request) {
List<String> errors = new ArrayList<String>();
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
errors.add(violation.getRootBeanClass().getName() + " " +
violation.getPropertyPath() + ": " + violation.getMessage());
}
ApiError apiError =
new ApiError(HttpStatus.BAD_REQUEST, ex.getLocalizedMessage(), errors);
return new ResponseEntity<Object>(
apiError, new HttpHeaders(), apiError.getStatus());
}
Source
You must to change your userMap object for your validated User class in your controller:
public ResponseEntity<Users> registerUser(#RequestBody #Valid Users){
Users createdUser = userService.registerUser(user.firstName, user.lastName);
return ResponseEntity.ok().body(createdUser).build();
}
This should returns the error messages for not valid fields only in a JSON structure.
A good practice is the use of DTOs instead Entities clases for Controllers requests and responses, you can read more about that here:
https://www.amitph.com/spring-entity-to-dto/
In this way you can choose those fields from your Entities that you want to show.

Spring #OneToMany problems

Doing a project with parcel service. I created OrderItem API and Dispatcher API. Now, I want to connect then by relations. The idea is: dispatcher can have many orderItems. OrderItem can only have one dispatcher. If you delete dispatcher, his order items also has to go out.
I have already created a little bit, but I'm so messed up here and can't finish this thing logically. Would someone give me some ideas on how I should attack this problem.
Do I need to put relations both sides or only to one of them?
When do I need to create constructors with arguments? Because in entity class you have to have no arg constructors...?
OrderItem class:
#Entity
public class OrderItem {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#NotBlank(message = "Order weight is required")
private String weight;
#NotBlank(message = "Order dimensions are required")
private String dimensions;
#NotBlank(message = "Order origin is required")
private String origin;
#NotBlank(message = "Order destination is required")
private String destination;
#NotNull(message = "Order comment cannot be null")
private String comment;
#ManyToOne
private Dispatcher dispatcher;
public OrderItem() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getWeight() {
return weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
public String getDimensions() {
return dimensions;
}
public void setDimensions(String dimensions) {
this.dimensions = dimensions;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
public String getDestination() {
return destination;
}
public void setDestination(String destination) {
this.destination = destination;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Dispatcher getDispatcher() {
return dispatcher;
}
public void setDispatcher(Dispatcher dispatcher) {
this.dispatcher = dispatcher;
}
}
OrderController class:
#RestController
#RequestMapping("/order")
public class OrderController {
#Autowired
OrderService service;
#Autowired
private MapValidationErrorService mapValidationErrorService;
#GetMapping("/{dispatcherId}/orders")
public List<OrderItem> getAllOrderItems(#PathVariable int dispatcherId) {
return service.getAllOrderItems(dispatcherId);
}
#PostMapping("/{dispatcherId}/orders")
public ResponseEntity<?> saveOrder(#Valid #RequestBody OrderItem orderItem, #PathVariable int dispatcherId, BindingResult result) {
ResponseEntity<?> errorMap = mapValidationErrorService.MapValidationService(result);
if (errorMap != null) {
return errorMap;
}
orderItem.setDispatcher(new Dispatcher(dispatcherId, "", "", ""));
service.insertOrUpdate(orderItem);
return new ResponseEntity<String>("Order was created successfully", HttpStatus.CREATED);
}
#PutMapping("/update")
public ResponseEntity<?> updateOrder(#Valid #RequestBody OrderItem orderItem, BindingResult result) {
ResponseEntity<?> errorMap = mapValidationErrorService.MapValidationService(result);
if (errorMap != null) {
return errorMap;
}
service.insertOrUpdate(orderItem);
return new ResponseEntity<String>("Order was updated successfully", HttpStatus.OK);
}
#GetMapping("/all")
public Iterable<OrderItem> getAllOrders() {
return service.findAllOrders();
}
#DeleteMapping("/{orderId}")
public ResponseEntity<String> deleteOrder(#PathVariable int orderId) {
if (service.findById(orderId) == null) {
throw new CustomErrorException("Order doesn't exist, check order id");
}
service.deleteOrder(orderId);
return new ResponseEntity<String>("Order with ID " + orderId + " was deleted", HttpStatus.OK);
}
#GetMapping("/{orderId}")
public ResponseEntity<OrderItem> getOrderById(#PathVariable int orderId) {
OrderItem item = service.findById(orderId);
if (service.findById(orderId) == null) {
throw new CustomErrorException("Order id not found - " + orderId);
}
return new ResponseEntity<OrderItem>(item, HttpStatus.OK);
}
}
Dispatcher class:
#Entity
public class Dispatcher {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#NotBlank(message = "Dispatcher first name is required")
private String firstName;
#NotBlank(message = "Dispatcher last name is required")
private String lastName;
#NotBlank(message = "Dispatcher email name is required")
private String email;
#NotBlank(message = "Dispatcher email is required")
private String password;
#NotBlank(message = "Dispatcher phone number is required")
private String phoneNumber;
public Dispatcher() {
}
public Dispatcher(int id, String firstName, String lastName, String email) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
DispatcherController class:
#RestController
#RequestMapping("/dispatcher")
public class DispatcherController {
#Autowired
DispatcherService service;
#Autowired
private MapValidationErrorService mapValidationErrorService;
#PostMapping("/save")
public ResponseEntity<?> saveDispatcher(#Valid #RequestBody Dispatcher dispatcher, BindingResult result) {
ResponseEntity<?> errorMap = mapValidationErrorService.MapValidationService(result);
if (errorMap != null) {
return errorMap;
}
service.insertOrUpdate(dispatcher);
return new ResponseEntity<String>("Dispatcher was created successfully", HttpStatus.CREATED);
}
#GetMapping("/all")
public Iterable<Dispatcher> getAllDispatchers() {
return service.findAllDispatchers();
}
#GetMapping("/{dispatcherId}")
public ResponseEntity<?> getDispatcherById(#PathVariable int dispatcherId) {
Dispatcher dispatcher = service.findById(dispatcherId);
if (service.findById(dispatcherId) == null) {
throw new CustomErrorException("Dispatcher id not found - " + dispatcherId);
}
return new ResponseEntity<Dispatcher>(dispatcher, HttpStatus.OK);
}
#DeleteMapping("/{dispatcherId}")
public ResponseEntity<?> deleteDispatcher(#PathVariable int dispatcherId) {
if (service.findById(dispatcherId) == null) {
throw new CustomErrorException("Dispatcher doesn't exist, check dispatcher id");
}
service.deleteDispatcher(dispatcherId);
return new ResponseEntity<String>("Order with ID " + dispatcherId + " was deleted", HttpStatus.OK);
}
#PutMapping("/update")
public ResponseEntity<?> updateDispatcher(#Valid #RequestBody Dispatcher dispatcher, BindingResult result) {
ResponseEntity<?> errorMap = mapValidationErrorService.MapValidationService(result);
if (errorMap != null) {
return errorMap;
}
service.insertOrUpdate(dispatcher);
return new ResponseEntity<String>("Dispatcher was updated successfully", HttpStatus.OK);
}
}
I think you have defined the relationship incorrectly. And yes you need to have no-args constructor. This helps hibernate to map the values from database to java objects when retrieving data from the database
Assuming you are going for a uni-directional mapping,
#Entity
public class OrderItem {
#ManyToOne( cascade = CascadeType.ALL )
#JoinColumn(name = <foriegn_key_column in orderItem table i.e. id>)
private Dispatcher dispatcher;
}
#Entity
public class Dispatcher {
private List<OrderItem > orders;
}
The main difference is that bidirectional relationship gives you access in both directions. so that you can access the other side without any queries. It works for cascade actions too.
The bidirectional #OneToMany generates better DML because the #ManyToOne owns the relationship.
Unidirectional #ManyToOneor bidirectional #OneToMany are more efficient than unidirectional #OneToMany.
Before JPA 2.0 this unidirection #OneToMany used a join table to manage the association between parent and child rows. So higher cost in read (3 tables join) and write (3 tables insertion).
Since JPA 2.0 for unidirectional #OneToMany you should use it in correlation with #JoinColumn
With the #JoinColumn the #OneToMany association controls the child table FK.. and so no need for extra junction table.
But performance wise there is no better than bidirectional associations.
Pros of unidirectional #OneToMany -> simplicity.
For your second question : NoArg is required only by the persistence framework (Hibernate for e.g). But you can (and should) use your own constructors to create consistent objects.

#RequestMapping not getting the parameters and values.Spring framework

I am trying to create an api with CRUD operations. For this created a User bean and a UserRepository which extends CrudRepository.
I tried to create one user but it is taking null values. One user id got created in database with null values.
Code:
#Controller // This means that this class is a Controller
#RequestMapping(path="/demo") // This means URL's start with /demo (after Application path)
public class MainController {
#Autowired // This means to get the bean called userRepository
// Which is auto-generated by Spring, we will use it to handle the data
private UserRepository userRepository;
/* #GetMapping(path="/add") // Map ONLY GET Requests
public #ResponseBody String addNewUser (#RequestParam String name
, #RequestParam String email) {
// #ResponseBody means the returned String is the response, not a view name
// #RequestParam means it is a parameter from the GET or POST request
User n = new User();
n.setName(name);
n.setEmail(email);
userRepository.save(n);;
return "Saved";
}*/
#RequestMapping("/create")
#ResponseBody
public String create(String email, String name) {
String userId = "";
try {
User user = new User(email, name);
userRepository.save(user);
userId = String.valueOf(user.getId());
}
catch (Exception ex) {
return "Error creating the user: " + ex.toString();
}
return "User succesfully created with id = " + userId;
}
#GetMapping(path="/all")
public #ResponseBody Iterable<User> getAllUsers() {
// This returns a JSON or XML with the users
return userRepository.findAll();
}
}
public interface UserRepository extends CrudRepository<User, Long> {
public User findByEmail(String email);
}
#Entity // This tells Hibernate to make a table out of this class
public class User {
public User(String email, String name) {
this.email = email;
this.name = name;
}
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private String email;
private String number;
#OneToMany(mappedBy="user")
private List <Location> locations;
public List<Location> getLocations() {
return locations;
}
public void setLocations(List<Location> locations) {
this.locations = locations;
}
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 getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
I am sending a post request from postman in JSON format.
http://localhost:8080/demo/create
{
"name" : "sid",
"email" : "sid#abc.com"
}
Response :
User succesfully created with id = 2
What is going wrong here? I am new to web development. Please help.
Thanks.
EDIT :
Same way I am trying to add a location for a particular user.
Created a location bean and manytoOne relation with a user entity.
The location is getting inserted but location id and user_id returns null.
#Entity
public class Location {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String location;
private double latitude;
public Location() {}
#ManyToOne(fetch = FetchType.LAZY)
private User user;
#Override
public String toString() {
return "Location [id=" + id + ", location=" + location + ", latitude=" + latitude + ", longitude=" + longitude
+ "]";
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
private double longitude;
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public char[] getId() {
// TODO Auto-generated method stub
return null;
}
}
#Controller // This means that this class is a Controller
#RequestMapping(path="/Locations") // This means URL's start with /demo (after Application path)
public class LocationController {
#Autowired // This means to get the bean called userRepository
// Which is auto-generated by Spring, we will use it to handle the data
private LocationRepository locationRepository;
private UserRepository userRepository;
#RequestMapping("/create")
#ResponseBody
public Location create(#RequestBody Location location) {
String locId = "";
Location newLocation = new Location();
try {
User user = userRepository(location.getUser()); //Get the parent Object
newLocation = new Location(); //Create a new Many object
newLocation.setLatitude(location.getLatitude());
newLocation.setLongitude(location.getLongitude());
newLocation.setLocation(location.getLocation());
newLocation.setUser(user);
locationRepository.save(newLocation);
locId = String.valueOf(newLocation.getId());
}
catch (Exception ex) {
// return "Error creating the user: " + ex.toString();
return newLocation;
}
return locationRepository.save(newLocation);
}
private User userRepository(User user) {
// TODO Auto-generated method stub
return null;
}
#GetMapping(path="/all")
public #ResponseBody Iterable<Location> getAllLocations() {
// This returns a JSON or XML with the users
return locationRepository.findAll();
}
}
public interface LocationRepository extends CrudRepository<Location, Long>{
}
Postman ;
http://localhost:8080/Locations/create
{
"latitude" : 15645.00,
"longitude" : 154645.00,
"location" : "miraroad",
"user": {
"id" : 6
}
}
Response
{
"id": null,
"location": "miraroad",
"latitude": 15645,
"user": null,
"longitude": 154645
}
Whats wrong here?
Please help. Thanks.
Try this. This should work
#RequestMapping("/create")
#ResponseBody
public String create(#RequestBody User user) {
String userId = "";
try {
userRepository.save(user);
userId = String.valueOf(user.getId());
} catch (Exception ex) {
return "Error creating the user: " + ex.toString();
}
return "User succesfully created with id = " + userId;
}
And create a No Args contructor in User class.

Neither BindingResult nor plain target object for bean name 'tweets' available as request attribute

I'm trying to add a global form to where a user can post. I get that error for some reason, been working on this for a while, it must be something with my controller but not sure
in home.jsp
<form:form modelAttribute= "tweets">
<form:input path="tweet" />
<input id="user" name="user" type="hidden" value="${user}"/>
<input type="submit" value="send" />
</form:form>
in TweetsController
public class TweetsController {
private TweetsService tweetsService;
#ModelAttribute("tweets")
// name for tweet form in home public Tweets
public Tweets construct() {
return new Tweets();
}
// //----------------------------------------------------------------------
#RequestMapping(value = "/")
public String newTweet(Model model) {
model.addAttribute("tweets", new Tweets());
return "/home";
}
#RequestMapping(method = RequestMethod.GET)
public String tweet(Model model) throws MessagingException {
// key value - attribute and the value of the attribute
// if key isn't passed, it will default to camelCased class name
model.addAttribute("tweets", new CreateTweet());
return "home";
}
#RequestMapping(method = RequestMethod.POST)
public String tweet(#ModelAttribute("tweets") CreateTweet tweet, BindingResult result,
RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
return "redirect:/";
}
tweetsService.createTweet(tweet);
return "redirect:/";
}
}
TweetsServiceImpl
#Service
#Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class TweetsServiceImpl implements TweetsService {
private TweetsRepository tweetsRepo;
#Autowired
private UserRepository userRepo;
#Autowired
public TweetsServiceImpl(UserRepository userRepo, TweetsRepository tweetsRepo) {
this.userRepo = userRepo;
this.tweetsRepo = tweetsRepo;
}
public TweetsRepository getTweetsRepo() {
return tweetsRepo;
}
public void setTweetsRepo(TweetsRepository tweetsRepo) {
this.tweetsRepo = tweetsRepo;
}
public UserRepository getUserRepo() {
return userRepo;
}
public void setUserRepo(UserRepository userRepo) {
this.userRepo = userRepo;
}
public List<Tweets> findAll() {
return tweetsRepo.findAll();
}
#Override
#Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void createTweet(CreateTweet createTweet) {
Tweets tweet = new Tweets();
tweet.setTweet(createTweet.getTweet());
tweet.setUser(createTweet.getUser());
tweetsRepo.save(tweet);
}
}
CreateTweet
public class CreateTweet {
#NotNull
#Size(min=1, max=500)
private String tweet;
#NotNull
private User user;
public String getTweet() {
return tweet;
}
public void setTweet(String tweet) {
this.tweet = tweet;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
User class
#Entity
#Table(name = "usr", indexes = { #Index(columnList = "email", unique = true) })
// using usr because in may conflict with the name of the class
public class User {
public static final int EMAIL_MAX = 250;
public static final int NAME_MAX = 50;
/*
* public static enum Role {
*
* UNVERIFIED, BLOCKED, ADMINISTRATOR
*
* }
*/
// primary key long, needs to be annotated with #Id
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
// add columns
#Column(nullable = false, length = EMAIL_MAX)
private String email;
#Column(nullable = false, length = NAME_MAX)
private String name;
// no length, the password will be encrypted to some longer value than the
// user enters
#Column(nullable = false)
private String password;
#OneToMany(mappedBy="user")
List<Tweets> tweets;
public List<Tweets> getTweets() {
return tweets;
}
public void setTweets(List<Tweets> tweets) {
this.tweets = tweets;
}
public void setUsername(String username) {
this.username = username;
}
#Column(nullable = false)
private String username;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEditable() {
User loggedIn = MyTools.getSessionUser();
if (loggedIn == null) {
return false;
}
return loggedIn.getId() == id;
}
public String getUsername() {
return username;
}
}
How can I get the form to show on the page and users can post?
Your TweetsController has mistakes. The way you wroted it your #ModelAttribute construct method will be called before every request, always making a new instance.
To fix this, you should annotate your controller with #SessionAttributes("tweets"). This way when your construct method is called it will store the model attribute in the model but also in the session store as well. Also, whenever the "tweets" model attribute is accessed it will be looked up in the session. For this reason your construct method will be called only initially.
#SessionAttributes("tweets") will also ensure that the model variable always exists in the request and your error will be resolved.
A confusing bit is that sometimes you store a class Tweets and sometimes CreateTweet as a "tweets" model attribute. Anyways, the following controller should work for you
#SessionAttributes("tweets")
public class TweetsController {
private TweetsService tweetsService;
#ModelAttribute("tweets")
// name for tweet form in home public Tweets
public Tweets construct() {
return new Tweets();
}
// //----------------------------------------------------------------------
#RequestMapping(value = "/")
public String newTweet(Model model) {
model.addAttribute("tweets", new CreateTweet());
return "/home";
}
#RequestMapping(method = RequestMethod.POST)
public String tweet(#ModelAttribute("tweets") CreateTweet tweet, BindingResult result,
RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
return "redirect:/";
}
tweetsService.createTweet(tweet);
return "redirect:/";
}
}

Categories