How can save order detail associated with the user and How can I return order data associated with the user details based the url parameters? - spring

I have created the User and Order entities as bellow. What I want to achieve is that if http://localhost:8080/users/username? is given I want to return only the user detail based on username provided. if http://localhost:8080/users/username?detail=true, I want to return user detail and order details for the username provided. How can I achieve this?
User.java
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String userName;
private String password;
private String firstName;
private String lastName;
private String gender;
private String lastLoggedIn;
#OneToMany
List<Order> listOfOrder;
//constructors
//getter and setter
}
Order.java
#Entity
public class Order
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private float amount;
private String createdAt;
private String deliveredDate;
//constructors
//getter and setter
}
Controller.java
//CREATE CUSTOMER
#RequestMapping(method = POST, value = "/create")
public ResponseEntity createCustomerDetails(#RequestParam String userName, String password, String firstName,
String lastName, String gender) {
String lastLogged = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());
User user = new User(userName, password, firstName, lastName, gender, lastLogged);
userRepository.save(user);
return ResponseEntity.status(OK).body(user.getId() + " User were successfully saved");
}
//CREATE ORDER
#RequestMapping(method = POST, value = "/order/{userName}")
public ResponseEntity createOrder(#PathVariable ("userName") String userName, #RequestParam float amount)
{
String createdAt = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());
String deliveredDate = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());
User user = orderService.findUser(userName);
if (!user.equals(null))
{
Order order = new Order(amount,createdAt,deliveredDate);
user.getListOfOrder().add(order);
return ResponseEntity.status(OK).body("order details were saved under "+user.getUserName() + " "+user.getFirstName());
}
return ResponseEntity.status(NOT_FOUND).body(null + " was not found");
}
//GET THE USER DETAILS
#RequestMapping(method = GET, value = "/users/{userName}")
public ResponseEntity getUserDetail(#PathVariable("userName") String userName,
#RequestParam(defaultValue ="none", required = false) String detail) {
if (!detail.equals("none")){
return .....;
}else {
return ........;
}
}
UserRepository
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
User findByUserName(String userName);
}

If you're ok with doing the serialization manually, you can employ JsonView to determine what gets serialized.
https://www.baeldung.com/jackson-json-view-annotation
User.java
import com.fasterxml.jackson.annotation.JsonView;
public class User {
#JsonView(Views.Lite.class)
private String name;
#JsonView(Views.Full.class)
private List<Order> orders;
}
Views.java
public class Views {
public static class Lite {}
public static class Full extends Lite {}
}
UserController.java
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class UserController {
#Autowired
private UserRepository userRepository;
#Autowired
private ObjectMapper mapper;
#GetMapping("/user/{username}")
public ResponseEntity<String> getUserDetail(#PathVariable String username, #RequestParam(required = false) String detail) throws JsonProcessingException {
User user = userRepository.findByUserName(username);
Class viewClass = Views.Lite.class;
if (!StringUtils.isEmpty(detail)) {
viewClass = Views.Full.class;
}
return ResponseEntity.status(HttpStatus.OK)
.body(mapper.writerWithView(viewClass).writeValueAsString(user));
}
}

Related

Json content for One post in Many to one rs request in spring boot

So i have two classes,
class User:
#Data
#NoArgsConstructor
#Entity
public class User {
#Id
#GeneratedValue
private int id;
private String displayName;
private String email;
private String gender;
private String Nationality;
private int age;
#OneToMany(mappedBy = "id", cascade = CascadeType.ALL)
private List<Event> createdEvents;
#OneToMany(mappedBy = "id", cascade = CascadeType.ALL)
private List<Reservation> clientReservations;
}
and class Event:
#Data
#Entity
public class Event {
#Id
#GeneratedValue
private int id;
private String eventName;
private Date eventDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_at", nullable = false, updatable = false)
#CreatedDate
private Date createdAt;
#ManyToOne
#JoinColumn(name="user_id")
private User user;
}
Contoller class:
#RestController
#RequestMapping("/event")
public class EventController {
#Autowired
private EventRepository eventRepository;
#PostMapping("/create")
public Event addEvent(#RequestBody Event event) {
return eventRepository.save(event);
}
}
Json:
"eventName": "theatre",
"eventDate": "2020-04-22",
"user": 3
im new to spring boot and what I've tried doesn't work.
now i want to add a single Event, and i need to pass a user id to reference the user who created the event, How can i do it ?
1.
In your Event class, add a constructor like this:
public Event(String eventName, Date eventDate, User user) {
this.createdAt = new DateTime();
this.eventName = eventName;
this.eventDate = eventDate;
this.user = user;
}
2.
Instead of passing Event as #RequestBody, consider creating a dto that handles submitted data on Post requests
public class EventDto {
private String eventName;
private String eventDateString;
private Long userId;
public String getEventName() {
return eventName;
}
public void setEventName(String eventName) {
this.eventName = eventName;
}
public String getEventDateString() {
return eventDateString;
}
public void setEventDateString(String eventDateString) {
this.eventDateString = eventDateString;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
}
Then you must replace #RequestBody Event event with #RequestBody EventDto eventDto
3.
Inject UserRepository, handle data, check that submitted user id exists and save your Event
#PostMapping("/create")
public Event addEvent(#RequestBody EventDto eventDto) throws ParseException {
var user = userRepository.findById(eventDto.getUserId());
if (user.isPresent()) {
Event event = new Event(eventDto.eventName.trim(), new SimpleDateFormat("yyyy-MM-dd").parse(eventDto.eventDateString), user.get());
eventRepository.save(event);
}
}

How to retrieve all data of the current User in controller?

I need take all data of the current user which is logged in and send it in JSON format into the route "/home". I was searching how to do it, but nothing.. I found that i can take only username and authorities there. Can someone help me to handle it? Thanks all.
There is my AuthController.java
// Getting all user data
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String getUsersDataById(Principal principal) {
return principal.getName();
}
There is my UserRepository
import com.example.demo.Models.Users;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<Users, Integer> {
Optional<Users> findByUsername(String username);
}
There are my services:
MyUserDetails.java
public class MyUserDetails implements UserDetails {
private String username;
private String password;
private String firstname;
private String lastname;
private String email;
private String last_login_date;
private String registration_date;
private String last_login_ip;
private Integer balance;
private Integer status;
private String brith_date;
private List<GrantedAuthority> authorities;
private boolean active;
public MyUserDetails(Users user) {
this.username = user.getUsername();
this.password = user.getPassword();
this.authorities = Arrays.stream(user.getRoles().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
this.active = user.isActive();
}
public MyUserDetails(String username, String firstname, String lastname, String email, String last_login_date, String registration_date, String last_login_ip, Integer balance, Integer status, String brith_date) {
this.username = username;
this.firstname = firstname;
this.lastname = lastname;
this.email = email;
this.last_login_date = last_login_date;
this.registration_date = registration_date;
this.last_login_ip = last_login_ip;
this.balance = balance;
this.status = status;
this.brith_date = brith_date;
}
public MyUserDetails() {
}
// and Override methods by default..
MyUserDetailsService
#Service
public class MyUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<Users> user = userRepository.findByUsername(username);
user.orElseThrow(() -> new UsernameNotFoundException("Not found: " + username));
return user.map(MyUserDetails::new).get();
}
}
There is Users.java with columns from table and geters and setters without constructor
#Entity
#Table(name = "users")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String username;
...
/// etc..
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
...
// etc..
Annotate your method with #AuthenticationPrincipal and use UserDetails.
#RequestMapping(value = "/home", method = RequestMethod.GET)
public Userdetails getUsersDataById(#AuthenticationPrincipal UserDetails userDetails) {
return userDetails;
}

I've a field which is not primary key id. how can i fetch data using JPA repository through that non primary key?

I've a model User. There's a field which is contact and it's a non primary key. How can i fetch data using this key? it's an unique key.
This is my model.
#Entity
#Table(name = "tbl_user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
long userId;
#Column(name = "name")
String name;
#Column(name = "email")
String email;
#Column(name = "contact")
String contact;
#Column(name = "category")
String category;
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
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 getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public User() {
}
}
This is the method inside Service layer.
public User getUserByContact(String contact) {
Optional<User> result = userRepository.findByContact(contact);
User user = result.get();
return user;
}
This is the repository.
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
#Query("select u from User u where u.contact = ?1")
User findByContact(String contact);
}
I'm getting an error on "select u from User u where u.contact = ?1" this portion under User and it's saying "cant resolve symbol User". Would appreciate any sort of help.
Leave out the #Query part, that part is not needed if you extend a JpaRepository. As stated in the documentation JPA derives the query from the method name.
I'm not sure whether this is an issue, but in your entity class you use a long for id and in your repository definition (JpaRepository<User, Long>) you use a Long. Correct me if this is not problematic.
If you want to use #Query, then the right approach would be to use #Param to define the variable
#Query("select u from User u where u.contact = :contactVar ", nativeQuery = true)
User findByContact(#Param("contactVar")String contactVar);

How to add a new role?

I have a user with admin and user roles, now I need to add ROLE_SUPPORT and restrict this role to only reading the list of users, how can I do this?
public class UserController {
#Autowired
UserService userService;
#RequestMapping(value = "getAll", method = RequestMethod.POST)
public List<User> getUsers() throws IOException {
return userService.getUsers();
}
#PostMapping("save")
#ResponseStatus(HttpStatus.OK)
public void save(#RequestBody User user) {
userService.save(user);
}
#RequestMapping(value = "delete", method = RequestMethod.POST)
public void delete(#RequestBody User user) {
userService.delete(user);
}
#RequestMapping(value = "getUser", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
#ResponseBody
public User getUser(#RequestBody RequestDto requestDto) throws IOException {
return userService.getUser(requestDto.getId());
}
I suppose a new method should be added to this controller, but I could be wrong
public class User extends BaseEntity<Integer> {
public enum Roles {
ADMIN
}
private String firstName;
private String lastName;
#Column(name = "username")
private String username;
#Convert(converter = PurshasedProductConverter.class)
private List<PurshasedProduct> purshasedProducts;
private String email;
private String activationCode;
#Convert(converter = AttachmentConverter.class)
private Attachment userAvatar;
public Attachment getUserAvatar() {
return userAvatar;
}
public void setUserAvatar(Attachment userAvatar) {
this.userAvatar = userAvatar;
}
#JsonProperty(access = Access.WRITE_ONLY)
private String password;
#JsonProperty(access = Access.WRITE_ONLY)
private String temporaryPassword;
#Convert(converter = StringArrayConverter.class)
private String[] roles;
private Date lastPasswordReset;
private Date dateCreated;
private Date dateUpdated;
private Date validatyTime;
private Boolean active;
public User() {
lastPasswordReset = dateCreated = dateUpdated = new Date();
roles = new String[]{"USER"};
}
That is, when requesting with the support role, a list of users should be returned.
Spring-Security provides this support by just adding #PreAuthorize annotation
#RequestMapping(value = "getAll", method = RequestMethod.GET)
**#PreAuthorize("hasRole('ROLE_SUPPORT')")**
public List<User> getUsers() throws IOException {
return userService.getUsers();
}

why I can't use string as id

I am trying to create a user model with a CrudRepository:
#Entity
public class User {
#Id
#GeneratedValue
private String username;
private String password;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
public interface UserRepository extends CrudRepository<User, String> {
}
However I got an 500 error every time I call findOne():
#Controller
public class UserController {
#Autowired
private UserRepository users;
#Override
#RequestMapping(value="/register", method=RequestMethod.POST)
public #ResponseBody User register(#RequestBody User userToRegister) {
String username = userToRegister.getUsername();
User user = users.findOne(id);
if (user != null) {
return null;
}
User registeredUser = users.save(userToRegister);
return registeredUser;
}
}
However if I just switch to an long type id instead of username itself then everything works. I think it's common to use string as id. So how to make this work?
I use the embedded hsql database. I didn't wrote any sql code.
The problem is that String username; is annotated with both #Id and #GeneratedValue. #Id means that is should be a primary key, fine it can be a String. But #GeneratedValue means that you want the system to automatically generate a new key when you create a new record. That's easy when the primary key is integer, all databases have a notion of sequence (even if the syntax is not always the same). But if you want String automatically generated keys, you will have do define your own custom generator.
Or if you have no reason for the #GeneratedValue annotation, simply remove it as suggested by Bohuslav Burghardt
Use column annotation like below by putting nullable False.
#Id
#GeneratedValue
#Column(name = "username", nullable = false)
private String username;

Resources