├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── README.md ├── bookRequest.json ├── pom.xml └── src ├── main ├── java │ └── com │ │ ├── business │ │ └── common │ │ │ └── Demo.java │ │ └── javatechie │ │ ├── InterviewQaApplication.java │ │ ├── advice │ │ ├── LogExecutionTracker.java │ │ ├── LogPayloadAdvice.java │ │ └── LoggingAdvice.java │ │ ├── annotation │ │ ├── LogPayloads.java │ │ └── TrackExecutionTime.java │ │ ├── client │ │ └── UserClient.java │ │ ├── common │ │ ├── User.java │ │ └── Volunteer.java │ │ ├── config │ │ ├── AppConfig.java │ │ ├── CorsConfig.java │ │ ├── DataSourceConfig.java │ │ ├── KafkaConfig.java │ │ ├── SecurityConfig.java │ │ ├── SwaggerConfig.java │ │ ├── WebClientConfig.java │ │ └── WebConfig.java │ │ ├── controller │ │ ├── ControllerDemo.java │ │ ├── DemoController.java │ │ ├── FileUploadController.java │ │ ├── FlightBookingController.java │ │ ├── ProductController.java │ │ ├── RestControllerDemo.java │ │ └── UserClientController.java │ │ ├── di │ │ ├── OrderInstanceFactory.java │ │ ├── OrderRepository.java │ │ ├── OrderRepositoryImpl1.java │ │ ├── OrderRepositoryImpl2.java │ │ ├── OrderService.java │ │ ├── RestClientService.java │ │ └── TrailerService.java │ │ ├── dto │ │ ├── Address.java │ │ ├── Author.java │ │ ├── Book.java │ │ ├── Company.java │ │ ├── ErrorDto.java │ │ ├── Geo.java │ │ ├── KafkaProps.java │ │ ├── Product.java │ │ └── UserResponse.java │ │ ├── entity │ │ └── UserDetails.java │ │ ├── exception │ │ └── ProductNotFoundException.java │ │ ├── handler │ │ ├── DuplicateProductException.java │ │ ├── ProductExceptionHandler.java │ │ └── ProductServiceException.java │ │ ├── processor │ │ └── PasswordValidationBeanPostProcessor.java │ │ ├── repository │ │ ├── DemoRepository.java │ │ └── UserDetailsRepository.java │ │ ├── scope │ │ ├── BeanScopeTestService.java │ │ ├── CustomThreadScope.java │ │ ├── ProtoTypeBean.java │ │ ├── RequestScopedBean.java │ │ ├── SessionScopedBean.java │ │ └── SingletonBean.java │ │ ├── service │ │ ├── DemoService.java │ │ └── ProductService.java │ │ └── validation │ │ ├── ProductTypeValidator.java │ │ └── ValidateProductType.java └── resources │ ├── application-prod.properties │ ├── application-stg.properties │ ├── application.properties │ ├── application.yaml │ └── templates │ ├── hello.html │ └── upload.html └── test └── java └── com └── javatechie └── InterviewQaApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Java-Techie-jt/spring-boot-interview-qa/d2a445b4b1782db579e11a5b807e8e8c0995b11f/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spring-boot-interview-qa 2 | -------------------------------------------------------------------------------- /bookRequest.json: -------------------------------------------------------------------------------- 1 | { 2 | "bookId": 123, 3 | "title": "Spring in Action", 4 | "publicationYear": 2022, 5 | "authors": [ 6 | { 7 | "authorId": 1, 8 | "name": "Craig Walls", 9 | "birthYear": 1978 10 | }, 11 | { 12 | "authorId": 2, 13 | "name": "John Doe", 14 | "birthYear": 1985 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.1.2 9 | 10 | 11 | com.javatechie 12 | interview-qa 13 | 0.0.1-SNAPSHOT 14 | interview-qa 15 | Demo project for Spring Boot 16 | 17 | 17 18 | 2022.0.4 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-web 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-actuator 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-validation 32 | 33 | 34 | org.projectlombok 35 | lombok 36 | true 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-test 41 | test 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-data-jpa 46 | 47 | 48 | com.mysql 49 | mysql-connector-j 50 | runtime 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-thymeleaf 55 | 56 | 57 | org.springdoc 58 | springdoc-openapi-starter-webmvc-ui 59 | 2.0.4 60 | 61 | 62 | org.springframework.cloud 63 | spring-cloud-starter-openfeign 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-starter-webflux 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | org.springframework.cloud 80 | spring-cloud-dependencies 81 | ${spring-cloud.version} 82 | pom 83 | import 84 | 85 | 86 | 87 | 88 | 89 | 90 | org.springframework.boot 91 | spring-boot-maven-plugin 92 | 93 | 94 | 95 | org.projectlombok 96 | lombok 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/main/java/com/business/common/Demo.java: -------------------------------------------------------------------------------- 1 | package com.business.common; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | @Component 6 | public class Demo { 7 | 8 | public Demo() { 9 | System.out.println("Demo class scanned !!!!"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/InterviewQaApplication.java: -------------------------------------------------------------------------------- 1 | package com.javatechie; 2 | 3 | import com.javatechie.common.User; 4 | import com.javatechie.common.Volunteer; 5 | import com.javatechie.config.DataSourceConfig; 6 | import com.javatechie.di.OrderService; 7 | import com.javatechie.scope.BeanScopeTestService; 8 | import com.javatechie.scope.CustomThreadScope; 9 | import com.javatechie.scope.SingletonBean; 10 | import jakarta.annotation.PostConstruct; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.beans.factory.annotation.Value; 13 | import org.springframework.beans.factory.config.Scope; 14 | import org.springframework.boot.CommandLineRunner; 15 | import org.springframework.boot.SpringApplication; 16 | import org.springframework.boot.autoconfigure.SpringBootApplication; 17 | import org.springframework.cloud.openfeign.EnableFeignClients; 18 | import org.springframework.context.ConfigurableApplicationContext; 19 | import org.springframework.core.env.Environment; 20 | import org.springframework.stereotype.Component; 21 | import org.springframework.stereotype.Controller; 22 | import org.springframework.stereotype.Repository; 23 | import org.springframework.stereotype.Service; 24 | import org.springframework.web.bind.annotation.RestController; 25 | 26 | //@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,AopAutoConfiguration.class}) 27 | @SpringBootApplication 28 | @EnableFeignClients 29 | public class InterviewQaApplication implements CommandLineRunner { 30 | 31 | @Value("${discount.offer.price}") 32 | private int discountPrice; 33 | 34 | 35 | @Autowired 36 | private Environment environment; 37 | 38 | @Autowired 39 | private DataSourceConfig config; 40 | 41 | 42 | @PostConstruct 43 | public void initLogic() { 44 | System.out.println("PostConstruct logic executed ...!"); 45 | //connection pool logic 46 | //kafka producer/consumer instantiate 47 | //data shedding 48 | //external API call 49 | } 50 | 51 | 52 | public static void main(String[] args) { 53 | //ConfigurableApplicationContext context = 54 | System.out.println("SpringApplication run() method ....... executed"); 55 | ConfigurableApplicationContext context = SpringApplication.run(InterviewQaApplication.class, args); 56 | //OrderService service = context.getBean("orderService", OrderService.class); 57 | // service.test(); 58 | 59 | // Scope scope = new CustomThreadScope(); 60 | // context.getBeanFactory().registerScope("threadScope", scope); 61 | // 62 | // Runnable childThread = () -> { 63 | // Volunteer v1 = context.getBean(Volunteer.class); 64 | // Volunteer v2 = context.getBean(Volunteer.class); 65 | // System.out.println("Hashcode of two object created by child thread " + v1.hashCode() + " & " + v2.hashCode()); 66 | // }; 67 | // new Thread(childThread).start(); 68 | 69 | // This code will be executed by main thread 70 | // Volunteer v1 = context.getBean(Volunteer.class); 71 | // Volunteer v2 = context.getBean(Volunteer.class); 72 | // System.out.println("Hashcode of two object created by main thread " + v1.hashCode() + " & " + v2.hashCode()); 73 | // 74 | //// 75 | //// 76 | SingletonBean sb1 = context.getBean(SingletonBean.class); 77 | SingletonBean sb2 = context.getBean(SingletonBean.class); 78 | System.out.println(sb1.getProtoTypeBean().hashCode()+" - "+sb2.getProtoTypeBean().hashCode()); 79 | 80 | // BeanScopeTestService service1=context.getBean(BeanScopeTestService.class); 81 | // BeanScopeTestService service2=context.getBean(BeanScopeTestService.class); 82 | // BeanScopeTestService service3=context.getBean(BeanScopeTestService.class); 83 | 84 | } 85 | 86 | @Override 87 | public void run(String... args) throws Exception { 88 | //DB connection 89 | //populate some data to the db 90 | // pre-processing logic you want to perform 91 | // System.out.println("DISCOUNT PRICE : "+environment.getProperty("discount.offer.price")); 92 | 93 | System.out.println("DISCOUNT PRICE : " + discountPrice); 94 | System.out.println("Environment variable : " + environment.getProperty("spring.profiles.active")); 95 | System.out.println("CONFIG VALUE : " + config); 96 | System.out.println("CommandLineRunner run() method ....... executed"); 97 | 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/advice/LogExecutionTracker.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.advice; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.aspectj.lang.JoinPoint; 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Before; 9 | import org.springframework.scheduling.annotation.Async; 10 | import org.springframework.stereotype.Component; 11 | 12 | @Aspect 13 | @Component 14 | @Slf4j 15 | public class LogExecutionTracker { 16 | 17 | @Around("@annotation(com.javatechie.annotation.TrackExecutionTime)") 18 | public Object logExecutionDuration(ProceedingJoinPoint pjp) throws Throwable { 19 | //before advice 20 | long startTime = System.currentTimeMillis(); 21 | Object obj = pjp.proceed(); 22 | //after advice 23 | long endTime = System.currentTimeMillis(); 24 | log.info(" method {} execution takes {} ms times to complete ", pjp.getSignature(), (endTime - startTime)); 25 | return obj; 26 | } 27 | 28 | } 29 | 30 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/advice/LogPayloadAdvice.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.advice; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Aspect 11 | @Component 12 | @Slf4j 13 | public class LogPayloadAdvice { 14 | 15 | @Around("@annotation(com.javatechie.annotation.LogPayloads)") 16 | public Object logPayloads(ProceedingJoinPoint pjp) throws Throwable { 17 | //before advice 18 | log.info("Request Body {} ", new ObjectMapper().writeValueAsString(pjp.getArgs())); 19 | Object obj = pjp.proceed(); 20 | //after advice 21 | log.info("Response Body {} ", new ObjectMapper().writeValueAsString(pjp.getArgs())); 22 | return obj; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/advice/LoggingAdvice.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.advice; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.aspectj.lang.JoinPoint; 7 | import org.aspectj.lang.annotation.*; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Aspect 11 | @Component 12 | @Slf4j 13 | public class LoggingAdvice { 14 | 15 | @Pointcut("execution(* com.javatechie.service.ProductService.*(..))") 16 | private void logPointcut() { 17 | } 18 | 19 | @Before("logPointcut()") 20 | public void logRequest(JoinPoint joinPoint) throws JsonProcessingException { 21 | log.info("Before Advice - class name {} ,method name {} ", joinPoint.getTarget(), joinPoint.getSignature().getName()); 22 | log.info("Before Advice - Request Body {} ", new ObjectMapper().writeValueAsString(joinPoint.getArgs())); 23 | } 24 | 25 | // @AfterReturning(value = "execution (* com.javatechie.controller.ProductController.*(..))",returning = "object") 26 | // public void logResponse(JoinPoint joinPoint,Object object) throws JsonProcessingException { 27 | // log.info("LoggingAdvice::logResponse class name {} ,method name {} ", joinPoint.getTarget(), joinPoint.getSignature().getName()); 28 | // log.info("LoggingAdvice::logResponse Response Body {} ", new ObjectMapper().writeValueAsString(object)); 29 | // } 30 | 31 | @AfterReturning(value = "execution (* com.javatechie.service.ProductService.*(..))") 32 | public void logResponse(JoinPoint joinPoint) throws JsonProcessingException { 33 | log.info("After Advice - LoggingAdvice::logResponse class name {} ,method name {} ", joinPoint.getTarget(), joinPoint.getSignature().getName()); 34 | log.info("After Advice - LoggingAdvice::logResponse Response Body {} ", new ObjectMapper().writeValueAsString(joinPoint.getArgs())); 35 | } 36 | 37 | 38 | @AfterThrowing(value = "execution (* com.javatechie.service.ProductService.*(..))") 39 | public void logError(JoinPoint joinPoint) throws JsonProcessingException { 40 | log.info("Throws Advice - LoggingAdvice::logResponse class name {} ,method name {} ", joinPoint.getTarget(), joinPoint.getSignature().getName()); 41 | log.info("Throws Advice - LoggingAdvice::logResponse Response Body {} ", new ObjectMapper().writeValueAsString(joinPoint.getArgs())); 42 | } 43 | 44 | 45 | } -------------------------------------------------------------------------------- /src/main/java/com/javatechie/annotation/LogPayloads.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target(ElementType.METHOD) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface LogPayloads { 11 | } -------------------------------------------------------------------------------- /src/main/java/com/javatechie/annotation/TrackExecutionTime.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Target(ElementType.METHOD) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface TrackExecutionTime { 11 | } -------------------------------------------------------------------------------- /src/main/java/com/javatechie/client/UserClient.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.client; 2 | 3 | import com.javatechie.dto.UserResponse; 4 | import org.springframework.cloud.openfeign.FeignClient; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | 7 | import java.util.List; 8 | //https://jsonplaceholder.typicode.com/users 9 | @FeignClient(url="https://jsonplaceholder.typicode.com",name = "USER-CLIENT") 10 | public interface UserClient { 11 | 12 | @GetMapping("/users") 13 | public List getUsers(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/common/User.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.common; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.stereotype.Component; 7 | 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | 13 | public class User { 14 | 15 | private String username; 16 | private String password; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/common/Volunteer.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.common; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.context.annotation.Scope; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | @Scope("threadScope") 11 | public class Volunteer { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/config/AppConfig.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.config; 2 | 3 | import com.javatechie.common.User; 4 | import com.javatechie.service.DemoService; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.web.client.RestTemplate; 8 | 9 | @Configuration 10 | public class AppConfig { 11 | 12 | @Bean 13 | public DemoService demoService(){ 14 | return new DemoService(); 15 | } 16 | 17 | @Bean 18 | public User user() { 19 | User user = new User(); 20 | user.setUsername("john"); 21 | user.setPassword("t27t"); // The original, unencrypted password 22 | return user; 23 | } 24 | 25 | @Bean 26 | public RestTemplate template(){ 27 | return new RestTemplate(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/config/CorsConfig.java: -------------------------------------------------------------------------------- 1 | //package com.javatechie.config; 2 | // 3 | //import org.springframework.context.annotation.Bean; 4 | //import org.springframework.context.annotation.Configuration; 5 | //import org.springframework.web.servlet.config.annotation.CorsRegistry; 6 | //import org.springframework.web.servlet.config.annotation.EnableWebMvc; 7 | //import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 8 | // 9 | //@Configuration 10 | //@EnableWebMvc 11 | //public class CorsConfig implements WebMvcConfigurer { 12 | // 13 | // @Override 14 | // public void addCorsMappings(CorsRegistry registry) { 15 | // registry.addMapping("/api/**") 16 | // .allowedOrigins("*") // Add your front-end application's origin 17 | // .allowedMethods("GET", "POST", "PUT", "DELETE") 18 | // .allowedHeaders("Origin", "Content-Type", "Accept", "Authorization") 19 | // .allowCredentials(true) 20 | // .maxAge(3600); 21 | // } 22 | //} 23 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/config/DataSourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.config; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.boot.context.properties.ConfigurationProperties; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Configuration 11 | @ConfigurationProperties(prefix = "spring.datasource") 12 | @Data 13 | @AllArgsConstructor 14 | @Component 15 | @NoArgsConstructor 16 | public class DataSourceConfig { 17 | 18 | private String username; 19 | private String password; 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/config/KafkaConfig.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.config; 2 | 3 | import com.javatechie.dto.KafkaProps; 4 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.annotation.Profile; 8 | 9 | @Configuration 10 | public class KafkaConfig { 11 | 12 | @Bean 13 | //@Profile("dev") 14 | @ConditionalOnProperty(prefix = "app.active",name = "env",havingValue = "dev") 15 | public KafkaProps devKafkaProps() { 16 | KafkaProps props = new KafkaProps("2.237.64.90:8181", 8181, "dev-user-topic"); 17 | System.out.println("kafka dev bean initialized !"); 18 | return props; 19 | } 20 | 21 | @Bean 22 | // @Profile("stg") 23 | @ConditionalOnProperty(prefix = "app.active",name = "env",havingValue = "stg") 24 | public KafkaProps stgKafkaProps() { 25 | KafkaProps props = new KafkaProps("200.40.7.181:8282", 8282, "stg-user-topic"); 26 | System.out.println("kafka stg bean initialized !"); 27 | return props; 28 | } 29 | 30 | @Bean 31 | //@Profile("prod") 32 | @ConditionalOnProperty(prefix = "app.active",name = "env",havingValue = "prod") 33 | public KafkaProps prodKafkaProps() { 34 | KafkaProps props = new KafkaProps("247.69.84.118:8383", 8383, "prod-user-topic"); 35 | System.out.println("kafka prod bean initialized !"); 36 | return props; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | 5 | @Configuration 6 | public class SecurityConfig { 7 | 8 | public SecurityConfig() { 9 | System.out.println("SecurityConfig loaded ....."); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | 5 | @Configuration 6 | public class SwaggerConfig { 7 | 8 | public SwaggerConfig() { 9 | System.out.println("SwaggerConfig loaded ....."); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/config/WebClientConfig.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.reactive.function.client.WebClient; 6 | 7 | @Configuration 8 | public class WebClientConfig { 9 | 10 | @Bean 11 | public WebClient webClient() { 12 | return WebClient.builder().baseUrl("https://jsonplaceholder.typicode.com").build(); 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/config/WebConfig.java: -------------------------------------------------------------------------------- 1 | //package com.javatechie.config; 2 | // 3 | //import org.springframework.context.annotation.Configuration; 4 | //import org.springframework.http.MediaType; 5 | //import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; 6 | //import org.springframework.web.servlet.config.annotation.EnableWebMvc; 7 | //import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 8 | // 9 | //@Configuration 10 | //@EnableWebMvc 11 | //public class WebConfig implements WebMvcConfigurer { 12 | // 13 | // @Override 14 | // public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { 15 | // configurer 16 | // .favorParameter(false) 17 | // .defaultContentType(MediaType.APPLICATION_JSON) 18 | // .mediaType("json", MediaType.APPLICATION_JSON) 19 | // .mediaType("xml", MediaType.APPLICATION_XML); 20 | // } 21 | //} 22 | // 23 | //} 24 | // 25 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/controller/ControllerDemo.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.controller; 2 | 3 | import org.springframework.http.MediaType; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.ResponseBody; 7 | 8 | @Controller 9 | public class ControllerDemo { 10 | 11 | @GetMapping("/controller/welcome") 12 | //modelAndView 13 | public String welcome(){ 14 | return "hello"; 15 | } 16 | 17 | @GetMapping(value = "/greetingMessage",produces = MediaType.TEXT_PLAIN_VALUE) 18 | @ResponseBody 19 | public String message(){ 20 | return "Welcome to javatechie"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/controller/DemoController.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.controller; 2 | 3 | import com.javatechie.dto.KafkaProps; 4 | import com.javatechie.entity.UserDetails; 5 | import com.javatechie.repository.UserDetailsRepository; 6 | import com.javatechie.scope.SessionScopedBean; 7 | import io.swagger.v3.oas.annotations.Operation; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.web.bind.annotation.*; 11 | 12 | @RestController 13 | //@CrossOrigin(origins = "*") 14 | public class DemoController { 15 | 16 | // @Autowired 17 | // private RequestScopedBean requestScopedBean; 18 | @Autowired 19 | private SessionScopedBean sessionScopedBean; 20 | 21 | @Autowired 22 | private UserDetailsRepository repository; 23 | 24 | 25 | @GetMapping("/message") 26 | public String getMessage() { 27 | return sessionScopedBean.getMessage(); 28 | } 29 | 30 | @GetMapping("/users/name") 31 | public String checkBodyInGET(@RequestBody UserDetails userDetails) { 32 | return userDetails.getName(); 33 | } 34 | 35 | 36 | @PostMapping("/users") // not idempotent 37 | @Operation(description = "INSERT NEW USER") 38 | @ResponseStatus(HttpStatus.CREATED) 39 | public UserDetails addNewUser(@RequestBody UserDetails userDetails) { 40 | return repository.save(userDetails); 41 | } 42 | 43 | @PutMapping("/users/{id}") // idempotent 44 | @ResponseStatus(HttpStatus.NO_CONTENT) 45 | public UserDetails addAndUpdateUser(@PathVariable int id, @RequestBody UserDetails userDetails) { 46 | UserDetails existingUserDetails = repository.findById(id).get(); 47 | existingUserDetails.setName(userDetails.getName()); 48 | existingUserDetails.setAge(userDetails.getAge()); 49 | return repository.save(existingUserDetails); 50 | } 51 | 52 | // @GetMapping("/users") 53 | // @PostMapping 54 | // @PutMapping 55 | // @PatchMapping 56 | // @DeleteMapping 57 | // public ResponseEntity doSomeOperation(@RequestBody Object input){ 58 | // 59 | // } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/controller/FileUploadController.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.controller; 2 | 3 | import io.swagger.v3.oas.annotations.Hidden; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.ui.Model; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import org.springframework.web.multipart.MultipartFile; 10 | 11 | import java.io.IOException; 12 | import java.nio.file.Files; 13 | import java.nio.file.Path; 14 | import java.nio.file.Paths; 15 | 16 | @Controller 17 | public class FileUploadController { 18 | 19 | @GetMapping("/home") 20 | public String index() { 21 | return "upload"; 22 | } 23 | 24 | @PostMapping("/upload") 25 | @Hidden 26 | public String uploadFile(@RequestParam("file") MultipartFile file, Model model) throws IOException { 27 | Path path = Paths.get("/Users/javatechie/Desktop/Files/" + file.getOriginalFilename()); 28 | Files.write(path, file.getBytes()); 29 | model.addAttribute("message", "File has been uploaded successfully"); 30 | return "upload"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/controller/FlightBookingController.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.controller; 2 | 3 | import io.swagger.v3.oas.annotations.Hidden; 4 | import io.swagger.v3.oas.annotations.Operation; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.*; 7 | 8 | @RestController 9 | @RequestMapping("/flight") 10 | public class FlightBookingController { 11 | 12 | 13 | @PostMapping("/v1/bookNow") 14 | public ResponseEntity bookingTicket(@RequestBody Object request) { 15 | //execute actual logic 16 | return ResponseEntity.ok("Flight booking successfully completed !"); 17 | } 18 | 19 | @PostMapping("/v2/bookNow") 20 | @Hidden 21 | public ResponseEntity bookingTicket2(@RequestBody Object request) { 22 | //latestLogic 23 | return ResponseEntity.ok("New Flight booking approach successfully completed !"); 24 | } 25 | 26 | 27 | @PostMapping("/bookingNow") 28 | public ResponseEntity bookTicketVersionWithRequestParam(@RequestBody Object request, @RequestParam(name = "version") int version) { 29 | //execute actual logic 30 | if (version == 1) { 31 | return ResponseEntity.ok("This is version 1 of the resource"); 32 | } else { 33 | return ResponseEntity.ok("This is version 2 of the resource"); 34 | } 35 | } 36 | 37 | @PostMapping("/bookingNow2") 38 | public ResponseEntity bookTicketVersionWithHeaderParam(@RequestBody Object request, @RequestHeader(name = "Api-Version") int version) { 39 | //execute actual logic 40 | if (version == 1) { 41 | return ResponseEntity.ok("This is version 1 of the resource");//old 42 | } else { 43 | return ResponseEntity.ok("This is version 2 of the resource");//new 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/controller/ProductController.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.controller; 2 | 3 | import com.javatechie.dto.Product; 4 | import com.javatechie.service.ProductService; 5 | import io.swagger.v3.oas.annotations.Hidden; 6 | import jakarta.validation.Valid; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.dao.DataAccessException; 9 | import org.springframework.dao.DataRetrievalFailureException; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.*; 13 | import org.springframework.web.client.HttpClientErrorException; 14 | 15 | import java.util.List; 16 | 17 | @RestController 18 | @RequestMapping("/products") 19 | public class ProductController { 20 | 21 | @Autowired 22 | private ProductService service; 23 | 24 | @PostMapping 25 | public List saveProduct(@RequestBody @Valid Product product){ 26 | return service.saveProduct(product); 27 | } 28 | 29 | 30 | @GetMapping("/search/{productType}")//404 31 | public ResponseEntity getProducts(@PathVariable String productType) { 32 | List products = service.getProductByType(productType); 33 | return ResponseEntity.ok(products); 34 | } 35 | 36 | @GetMapping("/filter") 37 | public ResponseEntity findProducts(@RequestParam(value = "productType", required = false) String productType) { 38 | List productList = productType != null 39 | ? service.getProductByType(productType) 40 | : service.getProducts(); 41 | return ResponseEntity.ok(productList); 42 | } 43 | 44 | 45 | @GetMapping(produces = {"application/json","application/xml"}) 46 | @Hidden 47 | public List products(@RequestParam(value = "productType", required = false) String productType) { 48 | return productType != null 49 | ? service.getProductByType(productType) 50 | : service.getProducts(); 51 | } 52 | 53 | 54 | 55 | @GetMapping("/stores/{flag}/{storeId}") 56 | public String fetchStoreLocation(@PathVariable boolean flag,@PathVariable String storeId){ 57 | return service.fetchLocation(flag, storeId); 58 | } 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/controller/RestControllerDemo.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.controller; 2 | 3 | import com.javatechie.dto.Book; 4 | import org.springframework.web.bind.annotation.*; 5 | 6 | @RestController 7 | public class RestControllerDemo { 8 | 9 | @GetMapping("/restController/welcome") 10 | public String welcome(){ 11 | return "hello"; 12 | } 13 | 14 | @PostMapping("/books") 15 | public String processBook(@RequestBody Book book){ 16 | return book.getTitle()+" New book has been published on year "+book.getPublicationYear(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/controller/UserClientController.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.controller; 2 | 3 | import com.javatechie.client.UserClient; 4 | import com.javatechie.dto.UserResponse; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import org.springframework.web.client.RestTemplate; 10 | import org.springframework.web.reactive.function.client.WebClient; 11 | import reactor.core.publisher.Flux; 12 | 13 | import java.util.List; 14 | 15 | @RestController 16 | public class UserClientController { 17 | 18 | @Autowired 19 | private RestTemplate template; 20 | 21 | @Autowired 22 | private UserClient userClient; 23 | 24 | @Autowired 25 | private WebClient webClient; 26 | 27 | @GetMapping("/fetchMockUsers1") 28 | public List fetchMockUsersWithRestTemplate() { 29 | return template.getForObject("https://jsonplaceholder.typicode.com/users", List.class); 30 | } 31 | 32 | 33 | @GetMapping("/fetchMockUsers2") 34 | public List fetchMockUsersWithFeignClient() { 35 | return userClient.getUsers(); 36 | } 37 | 38 | @GetMapping("/fetchMockUsers3") 39 | public List fetchMockUsersWithWebclient() { 40 | Flux response = webClient.get() 41 | .uri("/users") 42 | .retrieve() 43 | .bodyToFlux(UserResponse.class); 44 | // Block and get the result (synchronous call - for demonstration purposes only) 45 | return response.collectList().block(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/di/OrderInstanceFactory.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.di; 2 | 3 | public class OrderInstanceFactory { 4 | 5 | public static OrderRepository getInstance() { 6 | return new OrderRepositoryImpl1(); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/di/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.di; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | public interface OrderRepository { 6 | 7 | public void saveOrder(); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/di/OrderRepositoryImpl1.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.di; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | @Repository 6 | public class OrderRepositoryImpl1 implements OrderRepository { 7 | @Override 8 | public void saveOrder() { 9 | System.out.println("OrderRepositoryImpl1::saveOrder() method executed.."); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/di/OrderRepositoryImpl2.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.di; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | @Component 6 | public class OrderRepositoryImpl2 implements OrderRepository{ 7 | @Override 8 | public void saveOrder() { 9 | System.out.println("OrderRepositoryImpl2::saveOrder() method executed.."); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/di/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.di; 2 | 3 | 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Lazy; 6 | import org.springframework.stereotype.Service; 7 | 8 | @Service 9 | public class OrderService { 10 | 11 | private RestClientService restClientService; 12 | 13 | @Autowired 14 | @Lazy 15 | public void setRestClientService(RestClientService restClientService) { 16 | this.restClientService = restClientService; 17 | } 18 | 19 | // private OrderRepository orderRepository; 20 | 21 | // // //Setter DI 22 | // //optional dependency injection 23 | // //not immutable in nature 24 | // //circular dependency can't resolve 25 | // @Autowired 26 | // public void setOrderRepository(OrderRepository orderRepository) { 27 | // this.orderRepository = orderRepository; 28 | // } 29 | // 30 | // //Constructor DI 31 | // //Mandatory dependency injection 32 | // //immutable in nature 33 | // //circular dependency can't resolve 34 | // @Autowired 35 | // public OrderService(OrderRepository orderRepository) { 36 | // this.orderRepository = orderRepository; 37 | // } 38 | // 39 | // 40 | // public void test() { 41 | // orderRepository.saveOrder(); 42 | // } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/di/RestClientService.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.di; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Lazy; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | public class RestClientService { 9 | 10 | private OrderService orderService; 11 | 12 | @Autowired 13 | @Lazy 14 | public void setOrderService(OrderService orderService) { 15 | this.orderService = orderService; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/di/TrailerService.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.di; 2 | 3 | import jakarta.annotation.Resource; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.stereotype.Service; 7 | 8 | @Service 9 | public class TrailerService { 10 | 11 | @Autowired 12 | //@Qualifier("orderRepositoryImpl2")//byType 13 | @Resource(name = "orderRepositoryImpl1")//byName 14 | private OrderRepository orderRepository; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/dto/Address.java: -------------------------------------------------------------------------------- 1 | 2 | package com.javatechie.dto; 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | public class Address { 12 | 13 | public String street; 14 | public String suite; 15 | public String city; 16 | public String zipcode; 17 | public Geo geo; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/dto/Author.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class Author { 11 | private long authorId; 12 | private String name; 13 | private int birthYear; 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/dto/Book.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class Book { 13 | private long bookId; 14 | private String title; 15 | private int publicationYear; 16 | private List authors; 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/dto/Company.java: -------------------------------------------------------------------------------- 1 | 2 | package com.javatechie.dto; 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | public class Company { 12 | 13 | public String name; 14 | public String catchPhrase; 15 | public String bs; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/dto/ErrorDto.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | import org.springframework.http.HttpStatus; 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | @Builder 12 | public class ErrorDto { 13 | 14 | private String status; 15 | private String errorMessage; 16 | private HttpStatus statusCode; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/dto/Geo.java: -------------------------------------------------------------------------------- 1 | 2 | package com.javatechie.dto; 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | public class Geo { 12 | 13 | public String lat; 14 | public String lng; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/dto/KafkaProps.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import org.springframework.stereotype.Component; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | public class KafkaProps { 12 | 13 | private String bootStrapServers; 14 | private int port; 15 | private String topicName; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/dto/Product.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.dto; 2 | 3 | import com.javatechie.validation.ValidateProductType; 4 | import jakarta.validation.constraints.*; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | 9 | import java.math.BigDecimal; 10 | import java.util.Date; 11 | 12 | @Data 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | public class Product { 16 | @NotNull(message = "id shouldn't be null") 17 | @NotEmpty(message = "id shouldn't be empty") 18 | private String id; 19 | @NotBlank(message = "name shouldn't be null or empty") 20 | private String name; 21 | @Min(value = 499,message = "price shouldn't be less than 499") 22 | @Max(value = 100000,message = "price shouldn't be exceed more than 100000") 23 | private double price; 24 | @NotBlank(message = "model shouldn't be null or empty") 25 | // @Pattern(regexp = "[A-Za-z0-9]+") 26 | private String model; 27 | @NotBlank(message = "productType shouldn't be null or empty") 28 | @ValidateProductType 29 | private String productType; 30 | 31 | // @Email 32 | // private String emailId; 33 | // 34 | // @AssertFalse 35 | // @AssertTrue 36 | // private boolean isActive; 37 | // 38 | // @Future 39 | // @Past 40 | // private Date birthDate; 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/dto/UserResponse.java: -------------------------------------------------------------------------------- 1 | 2 | package com.javatechie.dto; 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Data 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | public class UserResponse { 12 | 13 | public Integer id; 14 | public String name; 15 | public String username; 16 | public String email; 17 | public Address address; 18 | public String phone; 19 | public String website; 20 | public Company company; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/entity/UserDetails.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.entity; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.GeneratedValue; 5 | import jakarta.persistence.GenerationType; 6 | import jakarta.persistence.Id; 7 | import lombok.AllArgsConstructor; 8 | import lombok.Data; 9 | import lombok.NoArgsConstructor; 10 | 11 | @Data 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | @Entity 15 | public class UserDetails { 16 | @Id 17 | @GeneratedValue(strategy = GenerationType.IDENTITY) 18 | private int id; 19 | private String name; 20 | private int age; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/exception/ProductNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.exception; 2 | 3 | public class ProductNotFoundException extends RuntimeException{ 4 | 5 | public ProductNotFoundException(String message) { 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/handler/DuplicateProductException.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.handler; 2 | 3 | public class DuplicateProductException extends RuntimeException{ 4 | 5 | public DuplicateProductException(String message) { 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/handler/ProductExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.handler; 2 | 3 | import com.javatechie.dto.ErrorDto; 4 | import com.javatechie.exception.ProductNotFoundException; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ProblemDetail; 7 | import org.springframework.web.bind.MethodArgumentNotValidException; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.RestControllerAdvice; 10 | 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | @RestControllerAdvice 15 | public class ProductExceptionHandler { 16 | 17 | 18 | @ExceptionHandler(ProductNotFoundException.class) 19 | public ProblemDetail handleProductNotFoundException(ProductNotFoundException ex) { 20 | // return ErrorDto.builder() 21 | // .status("FAIL") 22 | // .errorMessage(ex.getMessage()) 23 | // .statusCode(HttpStatus.INTERNAL_SERVER_ERROR).build(); 24 | 25 | return ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage()); 26 | } 27 | 28 | @ExceptionHandler(DuplicateProductException.class) 29 | public ProblemDetail handleDuplicateProductException(DuplicateProductException ex) { 30 | // return ErrorDto.builder() 31 | // .status("FAIL") 32 | // .errorMessage(ex.getMessage()) 33 | // .statusCode(HttpStatus.INTERNAL_SERVER_ERROR).build(); 34 | 35 | return ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage()); 36 | } 37 | 38 | 39 | @ExceptionHandler(ProductServiceException.class) 40 | public ProblemDetail handleProductServiceException(ProductServiceException ex) { 41 | // return ErrorDto.builder() 42 | // .status("FAIL") 43 | // .errorMessage(ex.getMessage()) 44 | // .statusCode(HttpStatus.INTERNAL_SERVER_ERROR).build(); 45 | 46 | return ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage()); 47 | } 48 | 49 | @ExceptionHandler(MethodArgumentNotValidException.class) 50 | public Map handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) { 51 | Map errorMap = new HashMap<>(); 52 | ex.getBindingResult().getFieldErrors() 53 | .forEach(error -> { 54 | errorMap.put(error.getField(), error.getDefaultMessage()); 55 | }); 56 | return errorMap; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/handler/ProductServiceException.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.handler; 2 | 3 | public class ProductServiceException extends RuntimeException { 4 | 5 | public ProductServiceException(String message) { 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/processor/PasswordValidationBeanPostProcessor.java: -------------------------------------------------------------------------------- 1 | ///* 2 | //package com.javatechie.processor; 3 | // 4 | //import com.javatechie.common.User; 5 | //import org.springframework.beans.BeansException; 6 | //import org.springframework.beans.factory.config.BeanPostProcessor; 7 | //import org.springframework.stereotype.Component; 8 | // 9 | //@Component 10 | //public class PasswordValidationBeanPostProcessor implements BeanPostProcessor { 11 | // 12 | // @Override 13 | // public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 14 | //// if (bean instanceof User user) { 15 | //// if (!isValidPassword(user.getPassword())) { 16 | //// throw new IllegalArgumentException("Invalid password for user: " + user.getUsername()); 17 | //// } 18 | //// } 19 | // return bean; 20 | // } 21 | // 22 | // @Override 23 | // public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 24 | // return bean; 25 | // } 26 | // 27 | // private boolean isValidPassword(String password) { 28 | // // Implement your password validation logic here 29 | // // For example, check length, special characters, etc. 30 | // return password.length() >= 8 && password.matches(".*[@#$%!].*"); 31 | // } 32 | //} 33 | //*/ 34 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/repository/DemoRepository.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.repository; 2 | 3 | import org.springframework.stereotype.Repository; 4 | 5 | @Repository 6 | public interface DemoRepository { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/repository/UserDetailsRepository.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.repository; 2 | 3 | import com.javatechie.entity.UserDetails; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface UserDetailsRepository extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/scope/BeanScopeTestService.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.scope; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Scope; 5 | import org.springframework.stereotype.Component; 6 | 7 | @Component 8 | @Scope("prototype") 9 | public class BeanScopeTestService { 10 | 11 | public BeanScopeTestService() { 12 | System.out.println("BeanScopeTestService() instance created.."); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/scope/CustomThreadScope.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.scope; 2 | 3 | import org.springframework.beans.factory.ObjectFactory; 4 | import org.springframework.beans.factory.config.Scope; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | public class CustomThreadScope implements Scope { 10 | 11 | 12 | CustomThreadLocal customThreadLocal = new CustomThreadLocal(); 13 | 14 | @Override 15 | public Object get(String str, ObjectFactory objectFactory) { 16 | System.out.println("Fetched object from scope"); 17 | 18 | @SuppressWarnings("unchecked") 19 | Map scope = (Map) customThreadLocal.get(); 20 | Object object = scope.get(str); 21 | if (object == null) { 22 | object = objectFactory.getObject(); 23 | scope.put(str, object); 24 | } 25 | 26 | return object; 27 | } 28 | 29 | @Override 30 | public Object remove(String name) { 31 | Map scope = (Map) customThreadLocal.get(); 32 | return scope.remove(name); 33 | } 34 | 35 | @Override 36 | public void registerDestructionCallback(String name, Runnable callback) { 37 | 38 | } 39 | 40 | @Override 41 | public Object resolveContextualObject(String key) { 42 | return null; 43 | } 44 | 45 | @Override 46 | public String getConversationId() { 47 | return null; 48 | } 49 | 50 | class CustomThreadLocal extends ThreadLocal { 51 | protected Map initialValue() { 52 | System.out.println("Initializing ThreadLocal"); 53 | return new HashMap(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/scope/ProtoTypeBean.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.scope; 2 | 3 | import org.springframework.context.annotation.Scope; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | @Scope("prototype") 8 | public class ProtoTypeBean { 9 | 10 | public ProtoTypeBean() { 11 | System.out.println("ProtoTypeBean() instantiate"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/scope/RequestScopedBean.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.scope; 2 | 3 | import org.springframework.context.annotation.Scope; 4 | import org.springframework.context.annotation.ScopedProxyMode; 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.web.context.WebApplicationContext; 7 | 8 | @Component 9 | @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) 10 | public class RequestScopedBean { 11 | 12 | private String message; 13 | 14 | public RequestScopedBean() { 15 | System.out.println("RequestScopedBean() constructor called !!"); 16 | this.message = "This is a request-scoped bean "; 17 | } 18 | 19 | public String getMessage() { 20 | return message; 21 | } 22 | 23 | public void setMessage(String message) { 24 | this.message = message; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/scope/SessionScopedBean.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.scope; 2 | 3 | import org.springframework.context.annotation.Scope; 4 | import org.springframework.context.annotation.ScopedProxyMode; 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.web.context.WebApplicationContext; 7 | 8 | import java.time.LocalDateTime; 9 | 10 | @Component 11 | @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) 12 | public class SessionScopedBean { 13 | private String message; 14 | 15 | public SessionScopedBean() { 16 | System.out.println("SessionScopedBean() constructor called !!"+ LocalDateTime.now()); 17 | this.message = "This is a Session-scoped bean "; 18 | } 19 | 20 | public String getMessage() { 21 | return message; 22 | } 23 | 24 | public void setMessage(String message) { 25 | this.message = message; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/scope/SingletonBean.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.scope; 2 | 3 | import org.springframework.beans.factory.ObjectFactory; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.beans.factory.annotation.Lookup; 6 | import org.springframework.context.ApplicationContext; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public class SingletonBean { 11 | 12 | // @Autowired 13 | // private ProtoTypeBean protoTypeBean; 14 | 15 | // @Autowired 16 | // ApplicationContext context; 17 | @Autowired 18 | private ObjectFactory protoTypeBeanObjectFactory; 19 | 20 | public SingletonBean() { 21 | System.out.println("SingletonBean() instantiated !!"); 22 | } 23 | 24 | public ProtoTypeBean getProtoTypeBean() { 25 | return getInstance(); 26 | } 27 | 28 | @Lookup 29 | public ProtoTypeBean getInstance(){ 30 | return null; 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/service/DemoService.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.service; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | //@Component 6 | public class DemoService { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/service/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.service; 2 | 3 | import com.javatechie.annotation.LogPayloads; 4 | import com.javatechie.annotation.TrackExecutionTime; 5 | import com.javatechie.dto.Product; 6 | import com.javatechie.exception.ProductNotFoundException; 7 | import com.javatechie.handler.DuplicateProductException; 8 | import com.javatechie.handler.ProductServiceException; 9 | import org.springframework.dao.DataRetrievalFailureException; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.web.client.HttpClientErrorException; 13 | 14 | import java.util.List; 15 | import java.util.Optional; 16 | import java.util.stream.Collectors; 17 | import java.util.stream.Stream; 18 | 19 | @Service 20 | public class ProductService { 21 | 22 | List productList = Stream.of( 23 | new Product("PTC49893", "Mobile", 9500, "SAMSUNG Galaxy F13 (Sunrise Copper, 64 GB)", "Electronics"), 24 | new Product("PTC25563", "Keyboard", 9500, "MAC Magic Keyboard", "Electronics"), 25 | new Product("PTC25372", "Books", 250, "It Ends With Us", "Education"), 26 | new Product("PTC49823", "Remote Control Toys", 699, "Wembley High Speed Mini 1:24 Scale Rechargeable Remote Control car with Lithium Battery", "Baby&Kids") 27 | ).collect(Collectors.toList()); 28 | 29 | 30 | public List getProducts() { 31 | return productList; 32 | } 33 | 34 | //joinpoint 35 | //pointcut (com.javatechie.service.saveProduct.*()) 36 | @TrackExecutionTime 37 | @LogPayloads 38 | public List saveProduct(Product product) { 39 | //TransactionAspect 40 | //loggingAspect 41 | //validationAspect 42 | //auditingAspect 43 | //notificationAspect 44 | boolean containsProductId = productList.stream() 45 | .map(Product::getId) 46 | .anyMatch(productId -> productId.equals(product.getId())); 47 | if (!containsProductId) { 48 | productList.add(product); 49 | } else { 50 | throw new DuplicateProductException("Product code already exist in system ! " + product.getId()); 51 | } 52 | return productList; 53 | } 54 | 55 | //Before Advice 56 | public List getProductByType(String productType) { 57 | //Transaction 58 | //logging 59 | //validation 60 | //auditing 61 | //notification 62 | List products = productList.stream() 63 | .filter(product -> product.getProductType().equals(productType)) 64 | .collect(Collectors.toList()); 65 | 66 | return Optional.of(products) 67 | .filter(list -> !list.isEmpty()) 68 | .orElseThrow(() -> new ProductNotFoundException("Products not available for the type " + productType)); 69 | 70 | } 71 | //After Advice -> consider Exception 72 | //After returning Advice -> No Exception 73 | //After throwing advice -> if any exception occurs 74 | //around advice -> Before + After returning 75 | 76 | public String fetchLocation(boolean flag, String storeId) { 77 | //Transaction 78 | //logging 79 | //validation 80 | //auditing 81 | //notification 82 | try { 83 | if (flag) { 84 | //fetch from application DB 85 | //logic 86 | throw new DataRetrievalFailureException("Store not available in system with storeId " + storeId); 87 | } else { 88 | //do rest api call to fetch store info by ID 89 | //logic 90 | throw new HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR, 91 | "Rest client error occurred while fetching store information"); 92 | } 93 | } catch (Exception exception) { 94 | throw new ProductServiceException(exception.getMessage()); 95 | } 96 | 97 | } 98 | 99 | 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/javatechie/validation/ProductTypeValidator.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.validation; 2 | 3 | import jakarta.validation.ConstraintValidator; 4 | import jakarta.validation.ConstraintValidatorContext; 5 | 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | public class ProductTypeValidator implements ConstraintValidator { 10 | @Override 11 | public boolean isValid(String productType, ConstraintValidatorContext constraintValidatorContext) { 12 | List productTypes = Arrays.asList("Electronics", "Education","Baby&Kids"); 13 | return productTypes.contains(productType); 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/java/com/javatechie/validation/ValidateProductType.java: -------------------------------------------------------------------------------- 1 | package com.javatechie.validation; 2 | 3 | import jakarta.validation.Constraint; 4 | import jakarta.validation.Payload; 5 | 6 | import java.lang.annotation.*; 7 | 8 | @Target({ElementType.FIELD,ElementType.PARAMETER}) 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Documented 11 | @Constraint(validatedBy = ProductTypeValidator.class) 12 | public @interface ValidateProductType { 13 | 14 | public String message() default "Invalid productType: It should be either Electronics OR Education OR Baby&Kids"; 15 | 16 | Class[] groups() default {}; 17 | 18 | Class[] payload() default {}; 19 | } -------------------------------------------------------------------------------- /src/main/resources/application-prod.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 2 | spring.datasource.url = jdbc:mysql://localhost:3306/javatechie_prod 3 | spring.datasource.username = root 4 | spring.datasource.password = Password 5 | spring.jpa.hibernate.ddl-auto = update 6 | 7 | spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect 8 | spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl -------------------------------------------------------------------------------- /src/main/resources/application-stg.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 2 | spring.datasource.url = jdbc:mysql://localhost:3306/javatechie_stg 3 | spring.datasource.username = root 4 | spring.datasource.password = Password 5 | spring.jpa.hibernate.ddl-auto = update 6 | 7 | spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect 8 | spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #debug=true 2 | 3 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 4 | spring.datasource.url = jdbc:mysql://localhost:3306/javatechie 5 | spring.datasource.username = root 6 | spring.datasource.password = Password 7 | spring.jpa.hibernate.ddl-auto = update 8 | 9 | spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect 10 | spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl 11 | 12 | 13 | 14 | 15 | # 16 | #spring.config.import=file:/Users/javatechie/Desktop/test.properties 17 | 18 | discount.offer.price= 20 19 | 20 | mylist= apple, banana, orange 21 | 22 | server.session.cookie.max-age= 1 23 | server.session.timeout= 1 24 | # 25 | ## Enable content negotiation 26 | #spring.mvc.contentnegotiation.favor-path-extension=true 27 | #spring.mvc.contentnegotiation.favor-parameter=true 28 | #spring.mvc.contentnegotiation.defaultContentType=application/xml 29 | 30 | app.active.env= prod 31 | 32 | 33 | #spring.profiles.active = stg -------------------------------------------------------------------------------- /src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8181 3 | 4 | 5 | 6 | discount: 7 | offer: 8 | price: 25 9 | 10 | myList: 11 | - orange 12 | - banana 13 | - apple 14 | - dfhjkd 15 | - hcdkh 16 | 17 | 18 | #spring: 19 | # profiles: 20 | # active: 21 | # - stg -------------------------------------------------------------------------------- /src/main/resources/templates/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | page loading 6 | 7 | 8 |

Welcome message from controller

9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/templates/upload.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | File Upload Example 7 | 84 | 85 | 86 |
87 |

File Upload Example

88 | 89 | 90 |
91 | 92 |
93 | 94 | 95 |
96 | 97 |
98 |
99 | 100 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /src/test/java/com/javatechie/InterviewQaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.javatechie; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class InterviewQaApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------