Swagger2 configuration spring boot won't working - java

I'm trying to add swagger to a project and when I access localhost:9999/swagger-ui returns "Whitelabel Error Page" always;
Here is my swagger configuration.
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.contact(new Contact("Vinicius Deluca", "", "vinidelucka#gmail.com"))
.title("Products-ms")
.description("")
.license("")
.licenseUrl("")
.version("1.0")
.build();
}
}
This is the first time I use this feature and can't see what I'm doing wrong. See some tutorials and looks like I did all in the same way. But still won't working.
My api runs direct after port 9999, without root package (localhost:9999/products is a get)
Controller:
#RestController
#RequestMapping("/products")
public class ProductController {
#Autowired
ProductService productService;
#GetMapping
public List<Product> productsList() {
List<Product> products = productService.productsList();
return products;
}
#GetMapping("/{id}")
public Optional<Product> searchProductById(#PathVariable String id) {
Optional<Product> product = productService.searchProductById(id);
return product;
}
#GetMapping("/search")
public List<Product> searchProducts(#RequestParam(required = false) Integer min_price,
#RequestParam(required = false) Integer max_price,
#RequestParam(required = false) String q) {
List<Product> products = productService.searchProducts(min_price, max_price, q);
return products;
}
#PostMapping
public ResponseEntity<Product> insertProduct(#RequestBody ProductForm form) {
Product product = productService.insertProduct(form);
return ResponseEntity.ok().body(product);
}
#PutMapping("/{id}")
#Transactional
public ResponseEntity<Product> updateProduct(#PathVariable String id, #RequestBody ProductForm form) {
Product product = productService.updateProduct(id, form);
return ResponseEntity.ok().body(product);
}
#DeleteMapping("/{id}")
#Transactional
public ResponseEntity<Product> deleteProduct(#PathVariable String id) {
ResponseEntity<Product> response = productService.deleteProduct(id);
return response;
}
}
application:
#SpringBootApplication
public class ProductMsApplication {
public static void main(String[] args) {
SpringApplication.run(ProductMsApplication.class, args);
}
}

Related

unit Test cases for spring boot application

I have written 1 unit Test for 1 single public method and need help from other methods of customer controller which I can refer to and write for other controllers and services.
CustomerController
#CrossOrigin(origins = "http://localhost:4200")
#RestController
#RequestMapping("/api/v1/")
public class CustomerController {
private static final Logger log = LoggerFactory.getLogger(CustomerController.class);
#Autowired
private CustomerRepository customerRepository;
public List<Customer> getAllcustomers(){
return customerRepository.findAll();
}
**public Customer createcustomer(#RequestBody Customer customer) {
log.info("inside customer add ***********");
return customerRepository.save(customer);
}**
**public ResponseEntity<Customer> getcustomerById(#PathVariable Long id) {
Customer customer = customerRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("customer not exist with id :" + id));
return ResponseEntity.ok(customer);
}**
**public ResponseEntity<Customer> updatecustomer(#PathVariable Long id, #RequestBody Customer customerDetails){
Customer customer = customerRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("customer not exist with id :" + id));
customer.setFullName(customerDetails.getFullName());
customer.setPhoneNumber(customerDetails.getPhoneNumber());
customer.setPhone2(customerDetails.getPhone2());
customer.setDistrict(customerDetails.getDistrict());
Customer updatedcustomer = customerRepository.save(customer);
return ResponseEntity.ok(updatedcustomer);
}**
**public ResponseEntity<Map<String, Boolean>> deletecustomer(#PathVariable Long id){
Customer customer = customerRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("customer not exist with id :" + id));
customerRepository.delete(customer);
Map<String, Boolean> response = new HashMap<>();
response.put("deleted", Boolean.TRUE);
return ResponseEntity.ok(response);
}**
}
Below is the Customer Model - which I am using
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String fullName;
private int phoneNumber;
private int phone2;
private String email;
private String district;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public int getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(int phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
UnitTest for Customer.
#ExtendWith(MockitoExtension.class)
public class CustomerControllerTest {
#Mock
CustomerRepository customerRepository;
#InjectMocks
CustomerController customerController;
#Test
public void testGetAllcustomers() {
when(customerRepository.findAll()).thenReturn(getCusts());
List<Customer> res = customerController.getAllcustomers();
assertEquals(res.size(),1);
}
public List<Customer> getCusts(){
List<Customer> custs = new ArrayList<>();
Customer c = new Customer();
c.setFullName("Dinga");
custs.add(c);
return custs;
}
}
Like the above Unit Test cases, I need other methods also. Marked in Bold for which I need Unit Test cases.
For testing a rest controller, it's recommended to use mockMvc. This acts like a rest client, but it does not actually start the server. Instead it uses the spring classes to call your code in almost the same way as if it were processing a real HTTP request. MoockMvc will perform the conversion of your data to Json and retrieve a Json result. Here's the official documentation, with some examples on how to use it: springdoc. Using ObjectMapper (or JacksonTester, which uses an ObjectMapper) you can deserialize the respone into objects.
#WebMvcTest(CustomerController.class)
#ComponentScan("com.your.base.package")
class ControllerTest{
#MockBean
private CustomerRepository customerRepository;
#Autowired
private MockMvc mockMvc;
#Test
void test1(){
when(customerRepository.findAll()).thenReturn(<whatever you want>)
// call mockMvc
this.mockMvc.perform(get("/")).andDo(print())
.andExpect(status().isOk());
}
}

Parameter 0 of constructor in .... Spring Boot

I am a fish in Spring Boot and Data Jpa, I Tried to create a basic Spring boot application but every time I am encountering the error. Can you help me?
That's my code:
Spring Boot Application class:
#SpringBootApplication
#ComponentScan(basePackages = "com.project.*")
#EnableJpaRepositories(basePackages = "com.project.repository.*")
#EntityScan(basePackages = "com.project.entities.*")
#EnableAutoConfiguration
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
Controller Class:
#RestController
#RequestMapping(value = "/api")
public class controller {
private IUserServices userServices;
#Autowired
public controller(IUserServices userServices) {
this.userServices = userServices;
}
#GetMapping(value = "/merhaba")
public String sayHello(){
return "Hello World";
}
#GetMapping(value = "/getall")
public List<User> getAll(){
return this.userServices.getAllUsers();
}
}
Repository Class:
#Repository
public interface UserRepository extends JpaRepository<User,Long> {
}
IServices Class:
#Service
public interface IUserServices {
void saveUser(User user);
List<User> getAllUsers();
}
ServicesImpl Class:
#Service
public class UserServicesImpl implements IUserServices{
private UserRepository userRepository;
#Autowired
public UserServicesImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public void saveUser(User user) {
this.userRepository.save(user);
}
#Override
public List<User> getAllUsers() {
return this.userRepository.findAll();
}
}
Entity Class:
#Entity
#Table(catalog = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
public User() {
}
public User(int id, String name) {
this.id = id;
this.name = name;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
#Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
AND THIS MY ERROR MESSAGE:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.project.services.UserServicesImpl required a bean of
type 'com.project.repository.UserRepository' that could not be found.
Action:
Consider defining a bean of type 'com.project.repository.UserRepository' in your
configuration.
Process finished with exit code 0
SO This is application properties file:
spring.jpa.properties.hibernate.dialect =
org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.show-sql=true
spring.datasource.url=jdbc:postgresql://localhost:5432/u
spring.datasource.username=postgres
spring.datasource.password=1234
spring.jpa.properties.javax.persistence.validation.mode = none
There are some issues that you should fix them.
First
When you have the spring boot application with #SpringBootApplication you don't need other stuff such as #EnableAutoConfiguration and etc, So remove them all.
You can read more about it here.
Second
You don't need to annotate your service interface with #Service, because you did it in the UserServicesImpl class.
Third
You defined id as an integer in your user entity but in the repository, you wrote your id as Long. It's wrong. It should be something like this.
#Repository
public interface UserRepository extends JpaRepository<User,Integer> {
}
Try the above solutions and let me know the result.

Spring Boot Application- Ambiguous mapping Cannot map method

i am creating a simple spring boot project when i run the project ran into the problem with Spring Boot Ambiguous mapping. Cannot map method. i have create two various controller those are student and course controller.i completly attached the error below.
i attached the full
**gub link here** https://github.com/raguram1986/SpringSecuritys
Full Error i attached below
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'studentController' method
com.example.studentmanagement.Controller.StudentController#saveStudent(Student)
to {POST [/save]}: There is already 'courseController' bean method
com.example.studentmanagement.Controller.CourseController#saveCourse(Course) mapped.
Controller
#Controller
public class StudentController {
#Autowired
private StudentService service;
#GetMapping("/Student")
public String viewHomePage(Model model) {
List<Student> liststudent = service.listAll();
// model.addAttribute("liststudent", liststudent);
System.out.print("Get / ");
return "Student";
}
#GetMapping("/addStudent")
public String add(Model model) {
List<Student> liststudent = service.listAll();
model.addAttribute("liststudent", liststudent);
model.addAttribute("student", new Student());
return "addstudent";
}
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String saveStudent(#ModelAttribute("student") Student std) {
service.save(std);
return "Student";
}
#RequestMapping("/edit/{id}")
public ModelAndView showEditStudentPage(#PathVariable(name = "id") int id) {
ModelAndView mav = new ModelAndView("addstudent");
Student std = service.get(id);
mav.addObject("student", std);
return mav;
}
#RequestMapping("/delete/{id}")
public String deleteStudentPage(#PathVariable(name = "id") int id) {
service.delete(id);
return "Student";
}
Student
#Entity
public class Student {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String stname;
private String course;
private int fee;
public Student() {
}
public Student(Long id, String stname, String course, int fee) {
this.id = id;
this.stname = stname;
this.course = course;
this.fee = fee;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getStname() {
return stname;
}
public void setStname(String stname) {
this.stname = stname;
}
public String getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
public int getFee() {
return fee;
}
public void setFee(int fee) {
this.fee = fee;
}
StudentRepository
#Repository
public interface StudentRepository extends JpaRepository<Student, Long>{
}
Service
#Service
public class StudentService
{
#Autowired
private StudentRepository repo;
public List<Student> listAll() {
return repo.findAll();
}
public void save(Student std) {
repo.save(std);
}
public Student get(long id) {
return repo.findById(id).get();
}
public void delete(long id) {
repo.deleteById(id);
}
}
In your StudentController you have the endpoint /save
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String saveStudent(#ModelAttribute("student") Student std) {
service.save(std);
return "Student";
}
But you haven't included the CourseController class in your question, which is mentioned in the error.
If you have defined an endpoint /save in that CourseController, then you have to rename it. Otherwise, when you invoke /save which controller needs to be invoked cannot be determined.
Add #RequestMapping above StudentController as below
#Controller
#RequestMapping("/students")
public class StudentController {
...
}
You are getting exception because there is already a mapping defined for path
/save
without being any controller mapping, so the first with root mapping is considered, but the next time it encounters same mapping it is already registered hence it is complaining. For clarity i'd suggest to add #RequestMapping to CourseController as well.
So now your course controller also becomes:
#Controller
#RequestMapping("/courses")
public class CourseController {
...
}
The best practice is to always add a request mapping at class level as well, like in your case, add a mapping like "/students" for SutdentController and "/course" for CourseController itself and then all other methods will be under that i.e. "/student/save" and then you will not face this issue anymore.

Inject SecurityContext in Service

I have my Application set-up as following:
Resource
#Path("/books")
public class BookResource {
#Inject
BookService bookService;
#Context
SecurityContext securityContext;
#GET
public Response getBooks() {
List<BookDTO> books = bookService.getAllBooks();
return Response.ok(books).build();
}
}
Service
public interface BookService {
List<BookDTO> getAllBooks();
}
ServiceImpl
public class BookServiceImpl implements BookService {
#Context
SecurityContext securityContext;
#Override
public List<BookDTO> getAllBooks() {
BookDTO book1 = new BookDTO("Catcher in the Rye");
BookDTO book2 = new BookDTO("Moby Dick");
return Arrays.asList(new Book[]{book1,book2});
}
}
In my Resource, the SecurityContext is injected and i can fetch the current user.
Is there a way to inject the SecurityContext outside of the Resource (the place where i put my path annotations)? If so, how can I do this?
I want to move my security back to the service and maybe repository too.
Update
I solved it by the following code, but I think it can get a lot better/cleaner.
BaseResource
public class BaseResource {
#Context
SecurityContext securityContext;
public class BaseRequest {
private Principal principal;
public BaseRequest() {
principal = securityContext.getUserPrincipal();
}
public Principal getPrincipal() {
return principal;
}
}
}
BookResource
public class BookResource extends BaseResource {
#Inject
BookService bookService;
#Path("/{id}")
public Response getBookById(#PathParam("id") Long id) {
BookDTO book = bookService.getBookById(new GetBookRequest(id));
return Response.ok(book).build();
}
public Response getAllBooks() {
List<BookDTO > books = bookService.getAllBooks(new GetAllBooksRequest());
return Response.ok(books).build();
}
public class GetBookRequest extends BaseRequest {
private Long id;
public GetBookRequest(Long id) {
super();
this.id = id;
}
public Long getId() {
return id;
}
}
public class GetAllBooksRequest extends BaseRequest {
public GetAllBooksRequest() {
super();
}
}
}
BookService
public interface BookService {
public List<BookDTO> getAllBooks(GetAllBooksRequest request);
public BookDTO getBookById(GetBookRequest request);
}
BookServiceImpl
#Named
public class BookServiceImpl implements BookService {
#Override
public List<BookDTO> getAllBooks(GetAllBooksRequest request) {
Principal principal = request.getPrincipal();
BookDTO book1 = new BookDTO();
book1.setName("Catcher in the Rye");
book1.setId(1L);
BookDTO book2 = new BookDTO();
book2.setName("Moby Dick");
book2.setId(2L);
return Arrays.asList( new BookDTO[]{ book1, book2 });
}
#Override
public BookDTO getBookById(GetBookRequest request) {
Principal principal = request.getPrincipal();
BookDTO book = new BookDTO();
book.setName("Catcher in the Rye");
book.setId(request.getId());
return book;
}
}
You don't need to inject anything. Use SecurityContextHolder insteed.
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
var principalName = authentication.getName();

Questions about Spring Security

I am actually beginner in Spring framework. For today i've faced with problems and i want ask you a couple questions to figure it out.
I want to make simple user login/authorisation app with Android client.
First of all I want to post my code:
Model:
#Entity
#Table(name = "Users")
public class User {
public User() {
}
#Id
#GeneratedValue(generator = "increment")
#GenericGenerator(name = "increment", strategy = "increment")
#Column(name = "Id", unique = true, nullable = false)
private long id;
#Column(name = "userName", nullable = false)
private String userName;
#Column(name = "userPassword", nullable = false)
private String userPassword;
#Transient
private String confirmPassword;
public long getId() {
return id;
}
public String getUsername() {
return userName;
}
public String getPassword() {
return userPassword;
}
public String getConfirmPassword() {
return confirmPassword;
}
public void setId(long id) {
this.id = id;
}
public void setName(String userName) {
this.userName = userName;
}
public void setPassword(String userPassword) {
this.userPassword = userPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}
}
Services:
User details:
#Service("userDetailsServiceImpl")
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
User user = userRepository.findByUserName(userName);
Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>();
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
}
}
Impl of UserSerice interface:
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
#Autowired
private BCryptPasswordEncoder passwordEncoder;
public void save(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
userRepository.save(user);
}
public User findByUserName(String userName) {
return userRepository.findByUserName(userName);
}
}
User validator:
#Component
public class UserValidator implements Validator {
#Autowired
private UserService userService;
#Override
public boolean supports(Class aClass) {
return User.class.equals(aClass);
}
#Override
public void validate(Object o, Errors errors) {
User user = (User) o;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username", "Required");
if (user.getUsername().length() < 8 || user.getUsername().length() > 32) {
errors.rejectValue("username", "Size.userForm.username");
}
if (userService.findByUserName(user.getUsername()) != null) {
errors.rejectValue("username", "Duplicate.userForm.username");
}
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "Required");
if (user.getPassword().length() < 8 || user.getPassword().length() > 32) {
errors.rejectValue("password", "Size.userForm.password");
}
if (!user.getConfirmPassword().equals(user.getPassword())) {
errors.rejectValue("confirmPassword", "Different.userForm.password");
}
}
}
Impl of SecurityService
#Service
public class SecurityServiceImpl implements SecurityService {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsService userDetailsService;
#Override
public String findLoggedInUsername() {
Object userDetails = SecurityContextHolder.getContext().getAuthentication().getDetails();
if (userDetails instanceof UserDetails) {
return ((UserDetails) userDetails).getUsername();
}
return null;
}
#Override
public void autoLogin(String username, String password) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
authenticationManager.authenticate(authenticationToken);
if (authenticationToken.isAuthenticated()) {
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
}
SecurityConfig:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
#ComponentScan("com.webserverconfig.user")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("userDetailsServiceImpl")
UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
And the lsat one -> Controller:
#RestController
#RequestMapping("/user")
public class UserController {
#Autowired
private UserService userService;
#Autowired
private SecurityService securityService;
#Autowired
private UserValidator userValidator;
#RequestMapping(value = "/registration", method = RequestMethod.POST)
#ResponseBody
#ResponseStatus(value = HttpStatus.CREATED)
public User registration(#RequestBody User user, BindingResult bindingResult, Model model) {
userValidator.validate(user, bindingResult);
if (bindingResult.hasErrors()) {
//What should i return here to my Android client ?
}
userService.save(user);
securityService.autoLogin(user.getUsername(), user.getConfirmPassword());
return user;
}
}
I am missing some classes here for saving space.
I am asking you for help me with my questions, please:
1) When i am trying to send JSON using Postman:
{
"id": 1,
"userName": "Andrew",
"userPassword": "apoyark123",
"confirmPassword": "apoyark123"
}
I am getting next erorr:
DefaultHandlerExceptionResolver - Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Unrecognized field "userName" (class com.webserverconfig.user.entity.User), not marked as ignorable (4 known properties: "id", "name", "password", "confirmPassword"])
at [Source: java.io.PushbackInputStream#ddd416; line: 3, column: 16] (through reference chain: com.webserverconfig.user.entity.User["userName"]); nested exception is com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "userName" (class com.webserverconfig.user.entity.User), not marked as ignorable (4 known properties: "id", "name", "password", "confirmPassword"])
at [Source: java.io.PushbackInputStream#ddd416; line: 3, column: 16] (through reference chain: com.webserverconfig.user.entity.User["userName"])
Am i missing some annotation ?
This issue resolved by Mehdi in the first comment. !!!
Please help me with second question.
2) I am haven't tested security validation part yet, because this code doesn't working, but i have a question -> How my client will understand that login/authorisation have gone wrong/good ?
If we take a look on controller's method registration(...) -> what should i return to the client if first "if" false ?
What if validation is not correct ? What should i return to the client and how ?

Categories

Resources