I have a legacy spring mvc application which is using spring jdbc as ORM. Now I wanted to use spring boot and instead of mvc I will be converting it in to RestAPI. I have problem with database query part. Using propertyplaceholder xml confi the external sql query properties file is configured in the old application. Using Spring boot and latest annotation methods how can I configure this. My understanding is
Place the query properties file in src/main/resources directory
In DAO create property name same as the key ( name ) of the sql.
create getter and setter for the key property
Is this is the right approach ? if yes if I use this how I will get the query in my DAO class ?. If not what is the best method.
It is not a good approach but you can do it in several ways and I am always approaching to use JPA when you work with database and spring boot
application.yml
emp:
eid: "select eid from employee"
name: "select ename from employee"
create a class for Employee under the model package
#ConfigurationProperties("emp")
#Getter
#Setter
public class Employee
{
private List<Integer> eid;
private List<String> ename;
}
create a bean instance for Employee under the config package
#Configuration
public class Config
{
#Bean
public Employee getEmployee()
{
return new Employee();
}
}
then you can call Employee instance whenever you need in your project
#RestController
public class EmpController
{
#Autowired
Employee emp;
}
After posting this question I didn't get much response. So I did some work from my side and the fixed it same way as I mentioned in the question. I didn't find any other method.
First a java class ApplicationPropertyConfig for PropertySourcesPlaceholderConfigurer . Property source file is my sql properties file.
#Configuration
#PropertySource("classpath:appSql.properties")
public class ApplicationPropertyConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
appSql.properties
selectallemployees=select * from employee;
created another class with name ApplicationSQLWrapper.java which is annotated with #Component. This contains the property name same as the sql properties key with #value annotation.
#Component
public class ApplicationSQLWrapper{
#Value("${selectallemployees}")
private String selectallemployees;
//getter and setter
This SQL's can be accessed from DAO class by creating an Object of the Component class.
Related
Spring Boot has a mechanism for accessing the contents of .properties (or YAML) files that one might want to include in an application.
I currently have a dbase.properties file (residing in src/main/resources) that contains the following information:
app.dbase.name=MyDbase
app.dbase.connect=jdbc:postgresql://localhost:5432
app.dbase.user=auser
app.dbase.password=mypassword
As described in various Spring Boot documents and examples, I have a configuration class that is defined below:
#Configuration
#PropertySource("dbase.properties")
#ConfigurationProperties(prefix = "app.dbase")
public class DbInfo
{
private String name;
private String connect;
private String user;
private String password;
// Getters and setters left out for brevity
}
Unfortunately, while the various documents and examples give good information on how to define a configuration
class, I have been unable to find any description on how to use it! Apparently, a Spring Boot web application
creates an instance of a configuration class upon startup (and it looks like it also initializes them with the
values from the properties file) but my attempts to guess how to access its contents when I need to have failed.
The method of doing so is probably simple, but no one seems to want to describe this method anywhere.
So: how does one access and use one of these configuration classes once they are instantiated?
Note that #ConfigurationProperties would require all of the properties in your file to be prefixed with 'app.dbase', as in 'app.dbase.username' and 'app.dbase.password'. If that's the case, the class you have now should work.
You would call it like this:
#Component
public class Component {
#Autowired DbInfo dbInfo;
public method() {
String username = dbInfo.username();
}
}
If you are having issues, you may be required to add this to a Configuration class:
#Configuration
public class Config {
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
...
}
You may also need to add 'classpath:' inside your annotation, as in: #PropertySource("classpath:dbase.properties"), assuming your properties file is in your src/main/resources.
Hi there I would ask you about recommended solutions of connecting another database in Spring + Hibernate.
In my case I have small application with its database and what I need to do is to obtain some data from another (large) db.
Currently I'm doing that with postgresql and dblink but now it would be better to move this query into code.
In near future I'll also need to invoke triggers on that database.
So the question is whats the best practice to solve this kind of connection problems?
To sum up, what I need:
invoke another database trigger
invoke dblink and obtain data from another database
You can try this to invoke another database from your spring boot application. So your base application will use MySQL and the secondary database will be Postgres.
If you are using spring-boot then create lib folder under the project folder (Same hierarchy of src). Add required jdbc jar in that folder.
Then, create DataBaseConfig class with #Configuration, inside that class create ComboPooledDataSource and JdbcTemplate bean.
Now in your service class just do Autowiring of that JdbcTemplate bean. Then, write SQL query to get value using this method queryForList
In pom.xml, you can map that external jar file like below
<dependency>
<groupId>com.mysql</groupId>
<artifactId>db2jcc</artifactId>
<version>11.1</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/mysql.jar</systemPath>
</dependency>
#Configuration
public class DatabaseConfig {
#Bean(name = "employeeDataBase")
#ConfigurationProperties(prefix = "employee.datasource")
public ComboPooledDataSource employeeDataSource() {
return new ComboPooledDataSource();
}
#Bean(name = "employeeTemplate")
public JdbcTemplate employeeTemplate(#Qualifier("employeeDataBase") DataSource ds) {
return new JdbcTemplate(ds);
}
}
#Service
public class EmployeeService {
#Autowired
#Qualifier("employeeTemplate")
JdbcTemplate employeeTemplate;
public void getEmployeeFromExternalDB() {
List<Map<String, Object>> maps = employeeTemplate.queryForList("SELECT * FROM EMPLOYEE");
}
}
//application.properties
employee.datasource.jdbc-url=${EMPLOYEE_URL}
employee.datasource.user=${EMPLOYEE_UNAME}
employee.datasource.password=${EMPLOYEE_PWD}
employee.datasource.driver-class=com.edb.Driver
employee.datasource.max-idle-time=6
employee.datasource.min-pool-size=3
employee.datasource.max-pool-size=15
employee.datasource.jdbcUrl=${EMPLOYEE_URL}
employee.datasource.driver-class-name=com.edb.Driver
I have a Class that accepts the following constructor
public Student(int id, String name, Map<String, List<String>> mapInject) {
super();
this.id = id;
this.name = name;
this.mapInject = mapInject;
}
And from spring Java Config, I am injecting the constructor args like below..
#Configuration
public class JavaConfig {
#Bean
public Employee getEmployeeBean() {
Map<String,List<String>> mapInject = new HashMap<String,List<String>>();
//Add map element
return new Employee(3123,"John",mapInject);
}
}
Am i doing constructor injection here? Is this the right way to do so?
I wouldn't use Spring to handle this bean creation, unless you want ALL employees to have the same id and name which I doubt.
The power behind Spring is its Dependency Injection (DI) where you define beans for providers such as database managers, services, etc. and inject those into your components. Defining a #Bean like you have there serves no purpose as now you can only inject employees with an id of 3123 and name John.
It's important to understand that just because you are using Spring it doesn't mean EVERYTHING needs to be handled as a bean - you will always need standard POJOs for housing and passing around state (such as your Employee class) which doesn't need to have anything to do with Spring.
Down the line you might have an EmployeeService for example which houses business logic to fetch employees from a database or something, this could then be configured as a bean so it can be injected across the application.
EDIT
#Configuration
public class JavaConfig {
#Bean
#Autowired //assuming a sessionfactory been is configured elsewhere
public EmployeeService employeeService(final SessionFactory sessionfactory) {
return new EmployeeService(sessionFactory);
}
}
You could then inject this anywhere (maybe in a controller for example):
#RestController
public class EmployeeController {
private final EmployeeService employeeService;
#Autowired
public EmployeeController(final EmployeeService employeeService) {
this.employeeService = employeeService;
}
}
Where the EmployeeController doesn't need to know or care that the userService has a DB connection and doesn't need to worry about configuring it as Spring will handle all of that.
From spring boot documentation, #ConfigurationProperties will
generate your own configuration metadata file from items annotated
with #ConfigurationProperties
I tried use #Configuration and #ConfigurationProperties separately on my configuration class.
#Component
//#Configuration
#ConfigurationProperties
#EnableSpringDataWebSupport
#EnableAsync
public class AppConfig {
...
}
I didn't see any noticable difference.
What's the usage of #ConfigurationProperties or #Configuration?
#Configuration is used to create a class the creates new beans (by annotating its methods with #Bean):
#Configuration
public class CustomConfiguration {
#Bean
public SomeClass someClass() {
return new SomeClass();
}
}
#ConfigurationProperties binds external configuration into the fields of the class which it annotates. It's common to use it with a #Bean method to create a new bean that encapsulates configuration which can be controlled externally.
Here's a real world example of how we've used it. Consider a simple POJO that holds some values related to connecting to ZooKeeper:
public class ZookeeperProperties
{
private String connectUrl;
private int sessionTimeoutMillis = (int) TimeUnit.SECONDS.toMillis(5);
private int connectTimeoutMillis = (int) TimeUnit.SECONDS.toMillis(15);
private int retryMillis = (int) TimeUnit.SECONDS.toMillis(5);
private int maxRetries = Integer.MAX_VALUE;
// getters and setters for the private fields
}
Now we can create a bean of type ZookeeperProperties and automatically populate it using external configuration:
#Configuration
public class ZooKeeperConfiguration {
#ConfigurationProperties(prefix = "zookeeper")
#Bean
public ZookeeperProperties zookeeperProperties() {
// Now the object we create below will have its fields populated
// with any external config that starts with "zookeeper" and
// whose suffix matches a field name in the class.
//
// For example, we can set zookeeper.retryMillis=10000 in our
// config files, environment, etc. to set the corresponding field
return new ZookeeperProperties();
}
}
The benefit of this is that it's less verbose than adding #Value to every field of ZookeeperProperties. Instead, you provide a single annotation on the #Bean method and Spring automatically binds any external configuration it finds with the matching prefix to the fields of that class.
It also lets different users of my class (i.e. anyone who creates a bean type of ZookeeperProperties) use their own prefix to configure the class.
The use case of ConfigurationProperties is for externalizing configuration.
#Configuration
Indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime.
#ConfigrationProperties
-- Is added to a class definition or a #Bean method in a #Configuration class if you want to bind and validate some external Properties (e.g. from a .properties file).
See the screenshot to differentiate #Value from #ConfigurationProperties.
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties
#Component
#PropertySources({ #PropertySource("classpath:mail.properties") })
public class A implements B {
#Value("${mail.team.address}")
private String teamAddress;
// has getter and setters .not shown for brevity.
Now when i call the class i get the value of teamAddress as NULL .But in the property file mail.team.address has some value.
My property file is present under src/main/resource folder
Making a call
A a = new A ();
a.someMethodinClassA();
You can not create instance of class by yourself when you want Spring to resolve #Value annotation.
See documentation:
Note that actual processing of the #Value annotation is performed by a BeanPostProcessor which in turn means that you cannot use #Value within BeanPostProcessor or BeanFactoryPostProcessor types. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation).
Simple solution for you: just annotate class with any #Component annotation and let Spring to create an instance of your class.
You can't create (with a "new" keywoard) for spring bean. If you do it like this, spring doesn't participate in the object creation and configuration, which means that there is no autowiring, the bean is not in Application Context, etc. And of course, #Value annotation won't be processed among other things
The better way is to inject the class A to the code that you used in your example:
A a = new A ();
a.someMethodinClassA();
Show become:
#Component
public class SomeClass {
private final A a;
public SomeClass(A a) {
this.a = a;
}
public void foo() {
a.someMethodinClassA();
}
}
You should read some basics around spring dependency injection. The class that you have autowired with #Component is scanned via component scanning and its object is created by spring container for you.
that is the reason you should not create the object yourself using new keyword.
wherever in your new class you want to use your class A object you can autowire it as below:
#Component
public class TestC{
private A a; // this object will be injected by spring for you
}