How can a result of a query be returned as JSON? Spring Boot - spring-boot

I have a method that should output me a JSON from a desired table. To keep the service as flexible as possible, I decided to use native queries, not to use entities and also to work without repositories. But so that I don't just get a list of objects from the database like this statement "final String sql = "SELECT * FROM " + schemaName + "." + tableName;", I extended my SQL statement with array_to_json. This is how I get a JSON from my DB.
Here is my method:
#Override
public List<Map<String, Object>> getList(String tableName, String schemaName) {
// final String sql = "SELECT * FROM " + schemaName + "." + tableName;
final String sql = "SELECT array_to_json(array_agg(" + tableName + ")) FROM " + schemaName + "." + tableName;
final Query query = em.createNativeQuery(sql);
final List<Map<String, Object>> queryResult = query.;
return queryResult;
}
When I execute my sql statement in the PG Admin then I get the following JSON:
[{"id":1,"analytic_id":1,"propertytype":"shape","min_val":null,"max_val":null,"string_val":"102941","case_else":0,"result":"kugel"},{"id":2,"analytic_id":1,"propertytype":"shape","min_val":null,"max_val":null,"string_val":"019283","case_else":0,"result":"rechteck"},{"id":3,"analytic_id":1,"propertytype":"shape","min_val":null,"max_val":null,"string_val":"0122343","case_else":0,"result":"prism"},{"id":6,"analytic_id":1,"propertytype":"color","min_val":0,"max_val":20,"string_val":null,"case_else":0,"result":"grun"},{"id":7,"analytic_id":1,"propertytype":"color","min_val":21,"max_val":50,"string_val":null,"case_else":0,"result":"gelb"},{"id":8,"analytic_id":1,"propertytype":"color","min_val":51,"max_val":80,"string_val":null,"case_else":0,"result":"hellblau"},{"id":9,"analytic_id":1,"propertytype":"color","min_val":81,"max_val":999,"string_val":null,"case_else":0,"result":"rot"},{"id":10,"analytic_id":1,"propertytype":"color","min_val":null,"max_val":null,"string_val":null,"case_else":1,"result":"lila"}]
Now for my question:
So I get a JSON from my query. But how do I rebuild my method so that I can display the result of my query in the GetRequest. It is important to me that I get a JSON with all data back and that the return type is compatible with OPENAPI 3.0.
Thanks in advance

Related

Is there a better way to execute this SQL statement in Spring using JdbcTemplate?

I have an SQL statement to select a BRAND_NAME based on an input parameter. The code goes something like this:
public ResponseEntity<List<Map<String, Object>>> getBrand(String brandName){
sql = "SELECT BRAND_NAME AS \"brandName\" FROM BRAND_E WHERE LOWER(BRAND_NAME) LIKE '%" + brandName + "%'";
return new ResponseEntity<List<Map<String, Object>>>(jdbc.queryForList(sql), HttpStatus.OK);
}
I've found out that this can probably cause SQL injection attacks, so I was wondering how to code this better.
Yes.If you directly use the request param on your sql it can lead to SQL injection attacks. We can always go with the prepared statement by adding a placeholder to where the values must be added.
Use queryForList(String sql, Object... args) or queryForList(String sql, Object[] args, Class<T> elementType)
Eg:-
String employeeId= "1";
String sql = "select id,name,address from employee where id = ?";
getJdbcTemplate(). queryForList(sql, new Object[]{employeeId}, Employee.class);

SQL UNINITIALIZED Error when Executing a SQL Builder Class - MyBatis Springboot

I have created an SQL statement using myBatis SQL builder, but I am to finding documentation on how to execute the string once its created. Currently, I have the following:
CONTROLLER:
#GetMapping("/simpleQuery/{schema}/{fromTable}")
public List <Object> getAllDataFromTable (#PathVariable String schema, #PathVariable String fromTable){
//return queryMapper.getSimpleQueryResults(schema, fromTable);
return queryService.selectDataFromTable(schema, fromTable);
}
SERVICE - where SQL string gets built
public List<Object> selectDataFromTable(String schema, String fromTable){
String selectDataFromTable = new SQL(){{
SELECT ("*");
FROM (schema + "." + fromTable);
}}.toString();
return queryMapper.getSimpleQueryResults(selectDataFromTable);
}
System.out.println(selectDataFromTable);
I've printed the SQL string out to the console and it looks like this:
SELECT *
FROM DB.SOMETABLENAME
UPDATE: I have also tried building the sql string like:
String selectDataFromTable = "SELECT * FROM " + schema +"." + fromTable;
So that the query is all one line but I still get the same results/error
MAPPER - sql string gets exectued
#Select("#{sql}")
List <Object> getSimpleQueryResults(String sql);
The query get executed but an error returns:
Invalid SQL type: sqlKind = UNINITIALIZED
So how do I get the SQL string to execute using mybatis in Springboot.
NOTE - I'm using annotation not XML.
Thank you

Spring JDBC : Inconsistent results when performing Order By

Any help would be greatly appreciated. I am working on a project using Spring JDBC for data access and am performing a simple query with an order by column expression, I am currently getting inconsistent results meaning the order by doesn't seem to be working. I have tried more than one database still no avail.
String sql = "select * from account where upper(name) like upper(:query) order by name asc";
MapSqlParameterSource params = new MapSqlParameterSource().addValue("query", "%" + query + "%");
List<Account> accountsSearched = namedParameterJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<Account>(Account.class));
Any ideas what could be the issue?
So the problem is not within your SQL code, but problem exist in search method implementation
Existing Code
public List<Account> search(String uncleanedQuery, int offset) {
String query = uncleanedQuery.replaceAll("([-+.^:,])","");
String sql = "select * from account where upper(name) like upper(:query) order by name asc";
MapSqlParameterSource params = new MapSqlParameterSource().addValue("query", "%" + query + "%");
List<Account> accountsSearched = namedParameterJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<Account>(Account.class));
Set<Account> accountSearchSet = new HashSet<Account>(accountsSearched);
List<Account> accounts = new ArrayList<Account>(accountSearchSet);
return accounts;
}
In the above code, we are fetching data correctly but assigning it to HashSet. HashSet does not respect ordering by name and generates random order for Account, due to which you are getting random order every time.
Solution 1:
There is no reason, you actually need Set. Using set just making your program slow. If you want to get DISTINCT data then modify SQL query.
public List<Account> search(String uncleanedQuery, int offset) {
String query = uncleanedQuery.replaceAll("([-+.^:,])","");
String sql = "select * from account where upper(name) like upper(:query) order by name asc";
MapSqlParameterSource params = new MapSqlParameterSource().addValue("query", "%" + query + "%");
List<Account> accountsSearched = namedParameterJdbcTemplate.query(sql, params, new BeanPropertyRowMapper<Account>(Account.class));
return accountsSearched;
}
Solution 2:
Still, you want to go with your approach then change code to use TreeSet and order based on the name
public List<Account> search(String uncleanedQuery, int offset) {
String query = uncleanedQuery.replaceAll("([-+.^:,])", "");
System.out.println("Search Query Called");
String sql = "select * from account where upper(name) like upper(:query) order by name";
MapSqlParameterSource params = new MapSqlParameterSource().addValue("query", "%" + query + "%");
List<Account> accountsSearched = namedParameterJdbcTemplate.query(sql, params,
new BeanPropertyRowMapper<Account>(Account.class));
Comparator<Account> comp = new Comparator<Account>() {
#Override
public int compare(Account a1, Account a2) {
return a1.getName().compareTo(a2.getName());
}
};
SortedSet<Account> accountSearchSet = new TreeSet<Account>(comp);
accountSearchSet.addAll(accountsSearched);
List<Account> accounts = new ArrayList<Account>(accountSearchSet);
return accounts;
}

selecting from data base according user inputs

servlets, oracle SQL developer .. i want to select data from database but accoeding to user inputs .. here is my code
public ResultSet f_items(Connection conn,String price) throws SQLException {
String query = "select * from items where price=? ";
Statement st=conn.createStatement();
ResultSet set=st.executeQuery(query);
return set;
}
the price is a column in the table ... but this code gives me an SQL exception which is
: ORA-01008: not all variables bound
any help ??
You do not set the expected price on the statement. It should look sth. like this:
....
String query = "select * from items where price='" + price + "'";
ResultSet set=st.executeQuery(query);
EDIT: like Multisync suggested, but with an explanation :)
String query = "select * from items where price=? ";
PreparedStatement st=conn.prepareStatement(query);
st.setString(1, price);
ResultSet set=st.executeQuery(query);
Why is using a prepared statement better?
concatenating user input into DB queries is a recipe for disaster, known as SQL injection.
methods of PreparedStatement like setString will escape the string value for you, preventing SQL injection.
public ResultSet f_items(Connection conn,String price) throws SQLException {
String query = "select * from items where price=? ";
PreparedStatement st=conn.prepareStatement(query);
st.setString(1, price);
ResultSet set=st.executeQuery(query);
return set;
}

How to make INSERT safer?

This is my method. As you can see I'm using native sql to execute INSERT queries.
public void addNews(String title, String content) {
Session session = null;
session = this.sessionFactory.getCurrentSession();
Query query = session
.createSQLQuery(
"INSERT INTO news VALUES(NULL,:title,:content,NULL)")
.setString("title", title).setString("content", content);
int updated = query.executeUpdate();
}
Is it safe? Or how can I improve my method?
Yes, setting values as parameters (setString() method) preventing from SQL-injections. Non secure sql-statement looks like this:
String query = "INSERT INTO news VALUES(NULL," + title + "," + content + ",NULL)";
Read more about SQL injections (and other types of vulnerabilities) you can here: https://www.owasp.org/index.php/SQL_Injection

Resources