Handson
1. Create spring boot appl to implement profiles
2. You are developing an online store application where you need to manage products. You need to create entities for Product and use Spring Data JPA to perform the following operations:
1. Add new products to a category.
2. List all products under a specific category.
3. Update product details.
4. Delete a product by its ID.
1. Springboot Profiling
In enterprise appl we have many env like dev, test, prod etc and each env needs different configuration related to that env and configured in application.properties, we cant configure everything in single file, so we have to use different properties file in different env and that concepts is called Profiling
a. we need to create different properties file related to env by application-profilename.properties (ie) application-dev.properties, application-prod.properties
b. By default springboot will read all configuration from application.properties, to configure which env properties file to read we have to provide
spring.profiles.active=profilename
@Value - used to read single property from properties file to the controller prg, it use Spring Expression Language
@Profile - used to programmatically control files based on profiles
application.properties
server.port=2000
message=Welcome default user
spring.profiles.active=prod, dev
#always choose last one
application-dev.properties
server.port=2001
message=Welcome development user
application-prod.properties
server.port=2002
message=Welcome production user
@RestController
public class ProfileController {
@Value("${server.port}") //SpEL
private int port;
@Value("${message}")
private String msg;
@GetMapping("/profile")
public String getProfileInfo() {
return "Hello from controller: "+msg+" runs on port: "+port;
}
}
@Configuration
@Profile("prod")
public class ProfileConfig {
@PostConstruct
public void print() {
System.out.println("This method should be printed only for prod profile");
}
}
By default springboot will read all configuration from application.properties or application.yaml
application.properties
1. It is represented as sequence of key value pairs
server.port=2000
server.servlet.context-path=/app
spring.profiles.active=prod
2. This file is supported only in Java lang
3. support key value pair but both key and value should be in the form of string
4. If we want to handle multiple profiles then we have to create separate properties file
application.yml
1. It is represented as hierarchial format
server:
port: 2000
servlet:
context-path: /app
spring:
profiles:
active: prod
2. This file is supported in Java, Python etc
3. Support scalar type(int, boolean, string, char), map, list, key value pair
4. We can handle multipl profiles in single yml file
server:
port: 2000
servlet:
context-path: /app
spring:
profiles:
active: prod
---
spring:
profiles: dev
server:
port: 2001
---
spring:
profiles: prod
server:
port: 2002
2. By default springboot will read all configuration from application.properties or application.yaml present inside src/main/resources folder. But if we create the properties file in different name and in different location, then how springboot can read those properties file
@PropertySource - used to read single properties file present in different name and in different location
@PropertySources - used to read multiple properties file present in different name and in different location
@Value - used to read single property from properties file to the controller prg, it use Spring Expression Language
@ConfigurationProperties - used to map entire properties from properties file to separate java bean object
Lombok Developer Tool - Java annotation library which helps to reduce boilerplate code like getter, setter, default constructor, arg constructor, toString, equals and hashcode, logging
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
student.properties in src/main/resources
student.id=100
student.name=Ram
student.address=Chennai
student.age=25
student1.properties in c:/Training folder
student.course=CSE
student.mark=89
@Configuration
//@PropertySource("classpath:student.properties")
//@PropertySource("file:\\C:\\Training\\student1.properties")
@PropertySources({
@PropertySource("classpath:student.properties"),
@PropertySource(file:\\C:\\Training\\student1.properties)
})
@ConfigurationProperties(prefix="student")
//@Getter
//@Setter
@Data //@Getter+@Setter
@NoArgsConstructor
@AllArgsConstructor
//@ToString
//@EqualsAndHashCode
public class StudentConfig {
private String name;
private String address;
private Integer age;
private String email;
private String course;
}
@RestController
public class StudentController {
@Value("${student.id}")
private Integer id;
@Value("${student.mark}")
private Integer mark;
@Autowired
StudentConfig config;
@GetMapping("/stud")
public String getStudentInfo() {
return id+" "+mark+" "+config.getName()+" "+config.getAddress();
}
}
@Value
1. Accessing properties one by one
2. Support SpEL
3. Loose binding/Loose Grammar is not supported (ie) property name should be matching
4. Validation of properties is not supported
5. support only scalar datatype
@ConfigurationProperties
1. Bulk injection of properties
2. Dosent support SpEL
3. Loose binding/Loose Grammar is supported (ie) property name should be matching but we can also change the property only with special char and cases
4. Validation of properties is supported
5. support all datatype as well as objects
To validate the properties we have to provide spring-boot-starter-validation dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
@Validated - used to validate the properties
@Valid - used to validate the nested class properties
mail.properties in src/main/resources
#Scalar datatype
mail.age=25
mail.first-name=Ram
mail.lastname=kumar
mail.middlename=T
#Complex datatype
mail.cc=efg@gmail.com,mno@gmail.com
mail.bcc=uvw@gmail.com,pqr@gmail.com
#Nested datatype
mail.credential.username=Ramu
mail.credential.password=abcd
@Configuration
@PropertySource("classpath:mail.properties")
@ConfigurationProperties(prefix="mail")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Validated
public class MailConfig {
@NotNull
private String to;
@NotNull
private String from;
@Max(value=40)
@Min(value=20)
private Integer age;
@NotNull
private String firstname; //Loose binding
private String LASTNAME; //Loose binding
private String middle_name; //Loose binding
private String[] cc;
private List<String> bcc;
@Valid
private Credential credential=new Credential();
@Data
public class Credential {
@NotNull
private String username;
@Size(min=4,max=8)
private String password;
}
}
@RestController
public class MailController {
@Autowired
MailConfig config;
@GetMapping("/mail")
public String getMailInfo() {
return config.getFrom()+" "+config.getLASTNAME()+" "+config.getBcc()+" "+config.getCredential().getPassword();
}
}
3. Springboot Interceptors
- used to intercept client request and response
- Interceptors are similar to Filters(only to Servlet), but interceptors are applied to the request that are sending to the controller
- We have to implement an interface called HandlerInterceptor and override 3 methods
1. preHandle() - perform any operation before sending request to controller
2. postHandle() - perform any operation before sending response to client
3. afterCompletion() - perform any operation after completing request and response
1. Create controller prg
@RestController
@Slf4j
public class EmployeeController {
@GetMapping("/emp")
public String getEmpInfo() {
log.info("Inside employee controller");
return "Employee Information";
}
}
2. Create Interceptor prg
@Component
@Slf4j
public class TimerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
log.info("Inside preHandle");
request.setAttribute("startTime", System.currentTimeMillis());
return HandlerInterceptor.super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("Inside postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
log.info("Inside afterCompletion");
long totalTime=System.currentTimeMillis()-(long)request.getAttribute("startTime");
System.out.println("Total time taken is : "+totalTime);
}
}
3. Configure interceptor for particular request
@Configuration
public class InterceptorConfig implements WebMvcConfigurer{
@Autowired
TimerInterceptor timerInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//registry.addInterceptor(timerInterceptor); //this interceptor will be invoked for all request
registry.addInterceptor(timerInterceptor).addPathPatterns("/emp","/stud","/mail");
}
}
Spring Data JPA
- used to persist data into database
- It is a library that adds as an extra layer of abstraction on top of JPA provider, mainly used to reduce work of developers at time of persisting the data
3 layers
1. Spring Data JPA - create JPA repository - 2 interface
a. JpaRepository<Entityclassname, datatype of PK> interface - used to perform CRUD as well as batch operation
- T getById(int id) - Deprecated
- T getOne(int id) - Deprecated
- T getReferenceById(int id) - fetch single object based on id
- List<> getAll() - fetch multiple object
- T saveAndFlush(T t) - store single object into db table
- void saveAllAndFlush(Iterable) - store multiple object into db table
- void deleteAllByIdInBatch(Iterable)
- void deleteAllInBatch()
b. JpaSpecificationExecutor<Entityclassname> interface - used to create dynamic queries
2. Spring Commons data layer - 3 interface
a. Repository<Entityclassname, datatype of PK> interface - marker interface
b. CrudRepository<Entityclassname, datatype of PK> interface - used to perform only CRUD operation
- T save(T t) - store single object into db table
- void saveAll(Iterable) - store multiple object into db table
- Optional findById(int id) - fetch single object based on id
- Iterable findAll() - return multiple objects
- boolean existsById(int id)
- boolean exists(T t)
- void deleteById(int id)
- void delete(T t)
- void deleteAll()
c. PagingAndSortingRepository<Entityclassname, datatype of PK> interface - used for pagination and sorting purpose
3. JPA Provider - vendors that provide implementation for JPA specification like Hibernate, iBatis, JDO etc
Repository interface
extends
CrudRepository interface
extends
PagingAndSortingRepository interface
extends
JpaRepository interface
1. Create Springboot project with spring data jpa, mysql driver, lombok dependency
2. Configure db info and hibernate properties in application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/aspirejava
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto= update
3. Create entity class
From SpringBoot 3.x onwards there is no javax, instead we use jakarta
@Entity
@Table(name="empl100")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
@Id
private Integer id;
private String name;
private String gender;
private String email;
private String dept;
private Double salary;
}
4. Create repository interface
public interface EmployeeRepository extends JpaRepository<Employee, Integer>{
}
5.
@SpringBootApplication
public class SpringDataJpaApplication implements CommandLineRunner{
@Autowired
EmployeeRepository empRepo;
public static void main(String[] args) {
SpringApplication.run(SpringDataJpaApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
//insertEmployee();
//fetchEmployee(100);
//fetchAllEmployee();
//updateEmployee(100);
deleteEmployee(100);
}
private void deleteEmployee(int i) {
if(empRepo.existsById(i)) {
//empRepo.deleteById(i);
Employee e=empRepo.findById(i).get();
empRepo.delete(e);
}
}
private void updateEmployee(int i) {
if(empRepo.existsById(i)) {
Employee e=empRepo.findById(i).get();
e.setSalary(25000.0);
empRepo.save(e);
}
}
private void fetchAllEmployee() {
List<Employee> l=empRepo.findAll();
l.forEach(System.out::println);
}
private void fetchEmployee(int i) {
Optional op=empRepo.findById(i);
System.out.println(op.get());
}
private void insertEmployee() {
/*Employee e1=new Employee(100,"Ram","male",ram@gmail.com,"HR",20000.0);
empRepo.save(e1);*/
List<Employee> l1=new ArrayList<>();
Employee e1=new Employee(101,"Sam","male",sam@gmail.com,"IT",30000.0);
l1.add(e1);
Employee e2=new Employee(102,"Saj","male",saj@gmail.com,"IT",35000.0);
l1.add(e2);
Employee e3=new Employee(103,"Amy","female",amy@gmail.com,"Sales",40000.0);
l1.add(e3);
Employee e4=new Employee(104,"Tim","male",tim@gmail.com,"HR",36000.0);
l1.add(e4);
Employee e5=new Employee(105,"John","male",john@gmail.com,"HR",45000.0);
l1.add(e5);
Employee e6=new Employee(106,"Lim","female",lim@gmail.com,"IT",42000.0);
l1.add(e6);
empRepo.saveAll(l1);
}
}
No comments:
Post a Comment