Hi everyone i was started to make from scratch my Spring Boot Application. I want to make Booking Application for my portfolio. I am a begginner in coding,past one year I have learning Java. I'm struggling whole day and I don't know where I have problem when I want to call getUser method in my Controller Class? Simply controller class doesn't see
method's is my Service Class.
Class's are in four different packages
com.booking.controller
com.booking.model
com.booking.repository
com.service
Here I have problem, simply it can't see service class.
#Controller
#RequestMapping(path = "/user")
public class UserController{
#Autowired
private UserRepository userRepository;
#GetMapping(path = "/add")
public #ResponseBody String addNewUser(#RequestParam String name,
#RequestParam String username,
#RequestParam String email, #RequestParam String password) {
User n = new User();
n.setName(name);
n.setUsername(username);
n.setEmail(email);
n.setPassword(password);
userRepository.save(n);
return "Saved";
}
#GetMapping(path = "/all")
public #ResponseBody Iterable<User> getAllUsers() {
return userRepository.findAll();
}
#RequestMapping("/{Id}")
public User getUser(#PathVariable Long id) {
return userRepository.getUser(id);
/*Here you can see problem*/
}
}
My User Class
#Entity
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column
private String name;
#Column
private String username;
#Column
private String email;
#Column
private String password;
public User() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
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;
}
}
**My Repository Class--
public interface UserRepository extends CrudRepository<User, Long> {
public List<User> findByUsername(String username);
}
My Service Class
#Service
public class UserService {
#Autowired
private UserRepository userRepository;
public List<User> getAllUsers(String username) {
List<User> users = new ArrayList<>();
userRepository.findByUsername(username).forEach(users::add);
return users;
}
public User getUser(Long id) {
return userRepository.findOne(id);
}
public void addUser(User user) {
userRepository.save(user);
}
public void updateUser(Long id, User user) {
userRepository.save(user);
}
public void deleteUser(Long id) {
userRepository.delete(id);
}
}
Related
I am trying to list users in my application based on role. I have an endpoint in my controller which tries to call my userService class .findByRoles method but I dont know how to put the role I want to without having the role as a string(wont work).
adminController.java method:
#GetMapping(path="/users")
public String showUsers( Model model){
var userList = (List<User>) userService.findByRoles("ROLE_TEACHER"); // dont know how to pass a role here
model.addAttribute("userList", userList);
return "users";
}
User.java:
#Entity
#Table(name = "user_table", schema = "public")
public class User {
#Id
#Column(name = "user_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long user_id;
#Column(name = "name")
private String name;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "email")
private String email;
#Column(name = "confirmed")
private boolean confirmed;
#ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH}, fetch = FetchType.EAGER)
#JoinTable(
name = "user_role_table",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id", referencedColumnName = "role_id"))
private Collection<Role> roles = new HashSet<>();
/*******************************************
* Setters and getters
*******************************************/
public Long getId() {
return user_id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setUsername(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword() {
return password;
}
public void setEmail(String email) {
this.email = email;
}
public String getEmail() {
return email;
}
public void setConfirmed(Boolean confirmed) {
this.confirmed = confirmed;
}
public Boolean getConfirmed() {
return confirmed;
}
public void setRoles(Collection roles) {
this.roles = roles;
}
public Collection<Role> getRoles() { return this.roles;
}
}
userRepository:
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
User findByEmail(String email);
User findByRoles(Role role);
}
roleRepository:
public interface RoleRepository extends JpaRepository<Role, Long> {
Role findByName(String name);
}
IUserService.java:
public interface IUserService {
User registerNewUserAccount(UserDto userDto);
List<User> findAll();
Optional<User> findById(Long id);
User findByRoles(Role role);
public void delete(Long id);
public User updateConfirmed(Long id);
}
UserService.java method:
#Override
public User findByRoles(Role role) {
return userRepository.findByRoles(role);
}
Any tips how I can go about to fix this issue?
After tweaking around with the classes I think the most logical method to fix the issue is to use roleRepository method findByName. Furthermore, created findAllByRoles in userRepository, IUserService & UserService for returning a list(check my comment on this answer).
Changed IUserService.java to:
public interface IUserService {
User registerNewUserAccount(UserDto userDto);
List<User> findAll();
Optional<User> findById(Long id);
List<User> findAllByRoles(String roles); //Added this new method (VERY IMPORTANT for returning multiple users)
User findByRoles(String roles);
public void delete(Long id);
public User updateConfirmed(Long id);
}
Changed UserService.java method to:
#Override
public User findByRoles(String roles) {
return userRepository.findByRoles(roleRepository.findByName(roles)); // Using roleRepository here
}
// Added below findAllbyRoles to return a list
#Override
public List<User> findAllByRoles(String roles){
return userRepository.findAllByRoles(roleRepository.findByName(roles));
}
Changed adminController.java method to:
#GetMapping(path="/users")
public String showUsers( Model model){
List<User> userList = userService.findAllByRoles("ROLE_STUDENT");
userList.addAll(userService.findAllByRoles("ROLE_TEACHER"));
model.addAttribute("userList", userList);
return "users";
}
I am having a problem with my retriveUser method. When I run finbyid method it returns the same repeated values. You can see my repository, user, and userService classes and the result below.
[![findbyid method result][1]][1]
My User Repository Class
package io.javabrains.springsecurity.jpa;
import io.javabrains.*;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import io.javabrains.springsecurity.jpa.models.User;
#Repository
public interface UserRepository extends JpaRepository<User, Integer> {
Optional<User> findByUserName(String userName);
}
My User Class
#Entity
#Table(name="app_user")
public class User implements Serializable {
#Id
#GeneratedValue(strategy =GenerationType.IDENTITY)
private int id;
private String userName;
private String password;
private boolean active;
private String role;
private String city;
public User(String userName, boolean active, String role, String city) {
super();
this.userName = userName;
this.active = active;
this.role = role;
this.city = city;
}
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinTable(name = "user_cities", joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "city_id", referencedColumnName = "id"))
private Collection<UserCity> usercities = new ArrayList<UserCity>() ;
public Collection<UserCity> getUsercities() {
return usercities;
}
public void setUsercities(Collection<UserCity> usercities) {
this.usercities = usercities;
}
public User() {}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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 boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
My Service Class
#RestController
public class HomeResource {
#Autowired
private BCryptPasswordEncoder bcryptPasswordEncoder;
#Autowired
private WeatherService weatherService;
#Autowired
private CityRepository cityRepository;
#Autowired
private UserRepository userRepo;
#GetMapping("/")
public String home() {
return ("<h1>Welcome</h1>");
}
#GetMapping("/user")
public String user() {
return ("Welcome User");
}
#GetMapping("/admin")
public String admin() {
return ("<h1>Welcome Admin</h1>");
}
#GetMapping("/getCities")
public List<UserCity> getCities()
{
return cityRepository.findAll();
}
#GetMapping("/users/{id}")
public ResponseEntity<User> retriveUser(#PathVariable int id){
Optional<User> a=userRepo.findById(id);
return new ResponseEntity<User>(a.get(),HttpStatus.OK);
}
Thanks in advance for your help.
Sincerely
[1]: https://i.stack.imgur.com/gNhO7.png
The repeated value is a nested user from the usercities collection in a User object.
The user (id: 1) has a usercities collection containing one UserCity object (cityName: 'bursa' and users containing the same user (id: 1)). Thus, the user (id: 1) is recursively displayed.
You can add #JsonIgnore annotation to your property (usercities in User or users in UserCity) to cut the recursion.
I have a problem with my spring boot application. I'm sending a request to get the key, but i get an error
java.lang.ClassCastException: class org.springframework.security.core.userdetails.User cannot be cast to class com.spring.springBlogProject.model.User (org.springframework.security.core.userdetails.User and com.spring.springBlogProject.model.User are in unnamed module of loader 'app')
at com.spring.springBlogProject.security.JwtProvider.generateToken(JwtProvider.java:28) ~[classes/:na]
I can’t understand what the problem is, I work with spring for the first time. I see that the received data cannot be reduced to the class that I created. What could be the problem? Below are my classes, I'm using Spring Boot (v2.3.1.RELEASE)
Thanks for your help.
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username).orElseThrow(()->
new UsernameNotFoundException("No user found with " + username));
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(),
true,true,true,true,
getAuthorities("ROLE_USER"));
}
private Collection<? extends GrantedAuthority> getAuthorities(String role_user) {
return Collections.singletonList(new SimpleGrantedAuthority(role_user));
}
}
#Table
public class User {
#Id
#GeneratedValue (strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String username;
#Column
private String password;
#Column
private String email;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
public class AuthService {
#Autowired
private UserRepository userRepository;
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private JwtProvider jwtProvider;
public void signUp(RegisterRequest registerRequest) {
User user = new User();
user.setUsername(registerRequest.getUsername());
user.setPassword(encodePassword(registerRequest.getPassword()));
user.setEmail(registerRequest.getEmail());
userRepository.save(user);
}
private String encodePassword(String password) {
return passwordEncoder.encode(password);
}
public String login(LoginRequest loginRequest) {
Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(),
loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authenticate);
return jwtProvider.generateToken(authenticate);
}
}
You have to convert it in UserDetails following way,
public class JwtUser implements UserDetails {
private final long id;
private final String email;
private final String phoneNo;
private final String username;
private final String password;
private final boolean enabled;
private final Collection<? extends GrantedAuthority> authorities;
public JwtUser(long userId, String email, String username, String phoneNo, String password, Boolean enabled, Collection<? extends GrantedAuthority> authorities) {
this.id = userId;
this.email = email;
this.phoneNo = phoneNo;
this.username = username;
this.password = password;
this.enabled = enabled;
this.authorities = authorities;
}
public long getId() {
return id;
}
public String getEmail() {
return email;
}
public String getPhoneNo() {
return phoneNo;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return enabled;
}
}
Replace :
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(),
true,true,true,true,
getAuthorities("ROLE_USER"));
with :
return new JwtUser(user.get().getUserId(), user.get().getEmail(), user.get().getUsername(),
user.get().getPhoneNo(), user.get().getPassword(), Boolean.TRUE, grantedAuthoritySet(user.get().getAuthorities()));
I have been trying to implement the administrator service spring security provides but I am finding it difficult, all my standard users can use the webapp but I cant seem to work out the sql required to authenticate that a user has a "ADMIN" role to allow them to view certain pages.
Any help advice would be greatly appreciated as I am new to this.
(Note: I am getting no errors in my console only the 403 username/password denied page)
My WebSecurityConfig file:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserLoginRepository userLoginRepository;
//http.authorizeRequests().antMatchers("/", "/home", "/registeruser").permitAll().antMatchers("/admin").hasRole("ADMIN")
#Autowired
DataSource dataSource;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/home", "/registeruser").permitAll().antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll().and().logout()
.permitAll();
http.exceptionHandling().accessDeniedPage("/403");
http.csrf().disable();
//disable csrf to allow communication (we also dont need for this fyp as its not live)
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//authorities at the moment is the manager i.e. 'Manager' from user_login
// String userByMailQuery = "SELECT user_type FROM user_login WHERE user_type = ?;";
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select user_name,password,user_status from user_login where user_name=?")
.authoritiesByUsernameQuery("select user_login_id, roles_id, role from user_login_roles, role where user_login_id=?");
}
}
The .authoritiesByUsernameQuery is the query im struggling with. The logic would be to check that a user has the role with the value of "ADMIN".
My UserLogin class:
#Entity
public class UserLogin {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private Long phone;
private String userName;
private String address;
private String password;
private boolean userStatus;
private String userType;
private String position;
#OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
public Set<Role> roles;
#OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
public Set<PlayerSeasonStat> playerStats;
public UserLogin()
{
}
public UserLogin(Long id, String firstName, String lastName, Long phone,
String userName, String address, String password,
boolean userStatus, String userType, String position,
Set<Role> roles, Set<PlayerSeasonStat> playerStats) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.phone = phone;
this.userName = userName;
this.address = address;
this.password = password;
this.userStatus = userStatus;
this.userType = userType;
this.position = position;
this.roles = roles;
this.playerStats = playerStats;
}
public Set<Role> getRoles() {
if (roles==null)
roles = new HashSet<>();
return roles;
}
public void setRole(Set<Role> roles) {
this.roles = roles;
}
public void addRole(Role role){
getRoles().add(role);
}
My role class:
#Entity
public class Role {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String role;
public Role()
{
}
public Role(Long id, String role) {
super();
this.id = id;
this.role = role;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
You can make a use of HandlerInterceptor where you can check login role is admin or not. with the method prehandle() of HandlerInterceptor interface you can handle the request and check the role and if login role does not match you can dispatch the request to 403 page
After login add Role Object to session, request.getSession().setAttribute("LOGGEDIN_USER_ROLE",roleObject) and you can make use of HandlerInterceptorAdapter
public class SecurityInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {
System.out.println("Interceptor: Pre-handle");
// Avoid a redirect loop for some urls
if(request.getRequestURI().equals("/admin-page")){
Role role = (Role) request.getSession().getAttribute("LOGGEDIN_USER_ROLE");
if(!role.getRole().equalsIgnoreCase("ADMIN")){
response.sendRedirect("/403/");
return false;
}
}
return true;
}
#Override
public void postHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {
}
}
I'm having problems trying to create a new record in my PostgreSQL database. I just want to POST to the REST service a new user (int:id, String:email, String:password) but, I'm having this error:
"exception": "org.springframework.dao.DataIntegrityViolationException",
"message": "could not execute statement; SQL [n/a]; constraint [id]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
These are my Java classes:
Domain
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String email;
private String password;
public User() {}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
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;
}
}
Controller
#RestController
#RequestMapping("/users")
public class UserController {
#Autowired
private UserService userService;
#RequestMapping(method = RequestMethod.GET)
public List<User> findAll() {
return userService.findAll();
}
#RequestMapping(method = RequestMethod.POST)
public User addUser(#RequestBody User user) {
userService.addUser(user);
return user;
}
}
Service
#Service
public class UserService {
#Autowired
private UserRepository userRepository;
public List<User> findAll() {
return (List<User>) userRepository.findAll();
}
public User addUser(User user) {
userRepository.save(user);
return user;
}
}
Repository
public interface UserRepository extends CrudRepository<User, Integer> {
// TODO
}
SQL
CREATE TABLE users(
id INT PRIMARY KEY NOT NULL,
email TEXT NOT NULL,
password CHAR(20) NOT NULL
);
Please, somebody help me, because I don't know how to tackle this issue.
I found the solution. I need to change the script for these one:
CREATE TABLE users(
id SERIAL PRIMARY KEY NOT NULL,
email TEXT NOT NULL,
password TEXT NOT NULL
);
Then, the Entity should be annotated with this:
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(columnDefinition = "serial")
private Long id;
private String email;
private String password;
public User() {}
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
SQL should be like this..
CREATE TABLE users(
id INT PRIMARY KEY BIGINT NOT NULL AUTO_INCREMENT,
email TEXT NOT NULL,
password CHAR(20) NOT NULL
);