Appending SQL data into datatables using JAVA in JSP - java

In my SQL Server I have the following result sets after all the condition filtering and sum query execution.
I would like to be shown like this in my page (refer to the screenshot below).
I have tried the below JAVA code that gave me the results that I appended into my datatables.
<%
ArrayList<String[]> rows = sqlq.querySQL();
String rowsetdate = new String();
String rowres1 = new String();
for(String[] rowset : rows) {
rowsetdate = rowset[0];
rowres1 = rowres1 + rowset[1]+ ",";
for(String rowres2 : rowset) {
rowres1 = rowres1 + rowres2 + ",";
}
rowres1 = rowres1.substring(0, rowres1.length()-1);
rowres1 = rowres1 + "|";
}
rowres1 = rowres1.substring(0, rowres1.length()-1);
%>
<tr>
<td><%if (rowres1 == null) out.print(""); else out.print(rowres1);%></td>
</tr>
sqlq.querySQL() is used to send my SQL query to JDBC in order for me to send query to my DB.
Photo below is the appended data in my datatables after the code execution, on the left is the Date and on the right is the data.
I tried some different code,
<%
ArrayList<String[]> rows = sqlq.querySQL();
for(String[] rowset : rows) {
<tr>
<td><%if (rowset[0] == null) out.print(""); else out.print(rowset[0]);%></td>
<td><%if (rowset[1] == null) out.print(""); else out.print(rowset[1]);%></td>
</tr>
}
%>
which did not achieve my expected results also, it returns the data like how I see it in my SSMS (check screenshot below)
What did I do wrong and how should I do it to get my expected outcome? (screenshot below)
Appreciate the help from all of you.

You can use a Map that its key is date and its value again is a Map. Inner Map uses trans as key and sumtot as value.
Map<String, Map<String, String>> mapByDate = new HashMap<>();
TreeSet<String> allTrans = new TreeSet<>();
for (String[] row : rows) {
Map<String, String> mapByDateAndTrans = mapByDate.get(row[0]);
if (mapByDateAndTrans == null) {
mapByDateAndTrans = new HashMap<>();
}
mapByDateAndTrans.put(row[1], row[2]);
mapByDate.put(row[0], mapByDateAndTrans);
allTrans.add(row[1]);
}
Here is a sample code to print data as you might expect:
System.out.println("Date/Trans: " + allTrans);
for (Map.Entry<String, Map<String, String>> mapByDateEntry : mapByDate.entrySet()) {
System.out.print(mapByDateEntry.getKey() + ": ");
Map<String, String> mapByTrans = mapByDateEntry.getValue();
for (String trans : allTrans) {
String sumtot = mapByTrans.get(trans);
if (sumtot != null) {
System.out.print("[ " + sumtot + " ]");
} else {
System.out.print("[ ]");
}
}
System.out.println();
}
The output:
Date/Trans: [11200, 11201, 11202]
2019-07-02: [ 136 ][ 18 ][ 14 ]
2019-07-03: [ 164 ][ 10 ][ 8 ]
Or we can generate an HTML table content:
StringBuilder tableBuilder = new StringBuilder("<table border = 1>");
// table header
tableBuilder.append("<tr>");
tableBuilder.append("<th>date/trans</th>");
for (String trans : allTrans) {
tableBuilder.append("<th>").append(trans).append("</th>");
}
tableBuilder.append("</tr>");
// table rows
for (Map.Entry<String, Map<String, String>> mapByDateEntry : mapByDate.entrySet()) {
tableBuilder.append("<tr>");
tableBuilder.append("<td>").append(mapByDateEntry.getKey()).append("</td>");
Map<String, String> mapByTrans = mapByDateEntry.getValue();
for (String trans : allTrans) {
String sumtot = mapByTrans.get(trans);
if (sumtot != null) {
tableBuilder.append("<td>").append(sumtot).append("</td>");
} else {
tableBuilder.append("<td></td>");
}
}
tableBuilder.append("<tr>");
}
tableBuilder.append("</table>");
System.out.println(tableBuilder.toString());
The Output:
<table border = 1><tr><th>date/trans</th><th>11200</th><th>11201</th><th>11202</th></tr><tr><td>2019-07-02</td><td>136</td><td>18</td><td>14</td><tr><tr><td>2019-07-03</td><td>164</td><td>10</td><td>8</td><tr></table>
If we save generated output as an HTML file, It maybe your desired result (screenshot below). Also you can change the code to be used in JSP:
To have an ordered Map by natural order of its keys, a TreeMap can be used. So to print the data ordered by date, we can construct a new TreeMap containing the mapByDate data:
TreeMap<String, Map<String, String>> sortedMapByDate = new TreeMap<>(mapByDate);
// table rows
for (Map.Entry<String, Map<String, String>> mapByDateEntry : sortedMapByDate.entrySet()) {
tableBuilder.append("<tr>");
tableBuilder.append("<td>").append(mapByDateEntry.getKey()).append("</td>");
Map<String, String> mapByTrans = mapByDateEntry.getValue();
for (String trans : allTrans) {
String sumtot = mapByTrans.get(trans);
if (sumtot != null) {
tableBuilder.append("<td>").append(sumtot).append("</td>");
} else {
tableBuilder.append("<td></td>");
}
}
tableBuilder.append("<tr>");
}

It's wasteful to do this in Java code, that's what the window functions are for in SQL. If you have a query like SELECT datet, trans, sumtout FROM ... you can use SUM with OVER:
SELECT DISTINCT datet, SUM(sumtout) OVER (PARTITION BY datet)
FROM ...
ORDER BY datet;

Related

How to safely extract nested values from YAML file using SnakeYaml?

I am working on extracting values from YAML Files in Java using the Snakeyaml library. Unfortunately, I am having a hard time extracting values from these files when I do not know the contents of the file in advance.
As such I am looking for a safe why to extract nested values from a given YAML File.
Here my approach:
Map<String, Object> dataMap = yaml.load(FileUtils.readFileToString(file, StrandardCharsets.UTF_8));
for(Map.Entry<String, Object> entry: dataMap.entrySet()) {
if(entry.getValue() instanceof Map<String, Object>) {
// Do something. Potentially loop again, because I do not know the depth of the File
} else {
// Get actual Value
}
}
I wrote this function that recursively reads all the fields in the yml file.
I have not tested it thoroughly, but I would say that it works as expected.
public static void readMapRec(Map<String,Object> map){
if(Objects.isNull(map) || map.entrySet().size()==0){
return;
}
for(Map.Entry<String,Object> entry: map.entrySet()){
try {
if (entry.getValue() instanceof List) {
for(int i = 0 ; i< ((List<?>) entry.getValue()).size();i++) {
Map<String, Object> casted = (Map<String, Object>) ((List<?>) entry.getValue()).get(i);
readMapRec(casted);
}
}
else {
System.out.println(entry.getKey() +" "+entry.getValue());
}
}catch (Exception ex){
System.out.println(ex.getMessage());
}
}
}
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream(new File("myFile.yml"));
Yaml yaml = new Yaml();
Map<String, Object> data = yaml.load(inputStream);
readYml(data);
}
So, If you have yml file like this:
id: 20
name: Bruce
year: 2020
address: Gotham City
department: Computer Science
courses:
- name: Algorithms
credits: 6
- name: Data Structures
credits: 5
- name: Design Patterns
credits: 3
books:
- ds:
- a: test
- b: test
- c:
- e: test
- f: test
You should see output like this:
id 20
name Bruce
year 2020
address Gotham City
department Computer Science
name Algorithms
credits 6
name Data Structures
credits 5
name Design Patterns
credits 3
a test
b test
e test
f test
I slightly adapted the function you proposed up top to catch indiscriminate cases:
private #NotNull Map<String[], Object> parseMap(#NotNull Map<String, Object> map, String[] previousRoot) {
Map<String[], Object> values = new HashMap<>();
if(map.entrySet().size()==0){
return values;
}
for(Map.Entry<String, Object> entry: map.entrySet()){
try {
LinkedList<String> list = new LinkedList<>(Arrays.asList(previousRoot));
list.add(entry.getKey());
String[] key = list.toArray(previousRoot);
if (entry.getValue() instanceof List) {
List<Map<String, Object>> objectItems = new ArrayList<>();
for(int i = 0 ; i< ((List<?>) entry.getValue()).size();i++) {
Map<String, Object> casted = (Map<String, Object>) ((List<?>) entry.getValue()).get(i);
if(casted.size() > 1) {
objectItems.add(casted);
} else {
values.putAll(parseMap(casted, key));
}
}
if(!objectItems.isEmpty()) {
System.out.println("Putting Key: " + Arrays.toString(key) + " with Value: " + objectItems);
values.put(key, objectItems);
}
}
else {
System.out.println("Putting Key: " + Arrays.toString(key) + " with Value: " + entry.getValue());
values.put(key, entry.getValue());
}
}catch (Exception ex){
System.out.println("Exception: " + ex.getMessage());
}
}
return values;
}
What do you think?
If you have any suggestions as to how it could be refined, I would be happy to hear them. :)

How to convert blob to image with Spring

I have a mysql db and I have a table called User and contains a column called pct that is of Type Blob.
I am using hibernate to carry out a native select query as follows:
public List<Map<String, Object>> queryExtraction(String sql, QWSInputParam[] qwsInputParams) {
sql = "SELECT user.name,user.pct FROM user user WHERE user.id = user.id and user.id in :PARAM0";
Query query = getSession().createSQLQuery(sql);
query.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
for (int i = 0; i < qwsInputParams.length; i++) {
LOGGER.info("PARAM" + i + ": " + Arrays.toString(qwsInputParams[i].getValues()));
query.setParameterList("PARAM" + i, qwsInputParams[i].getValues());
}
//LOGGER.info("Query extraction: " + query.toString());
//query.setTimeout(QUERY_TIME_OUT);
List<Map<String, Object>> list = query.list();
Object value = null;
for (Map<String, Object> map : list) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
value = entry.getValue();
System.out.println("0 " + entry.getValue());
}
}
return list;
}
I cannot use entity because it is a generic method that should cater for any table and therefore not related to a specific table.
Basically when the query is executed and for the column pct of type blob the following value is displayed:
[B#1a270232
Based on the post I understand this is a JNI type signature.
The pct value in the table is a picture as follows:
Is it possible to convert the value [B#1a270232 to a base64 so that I can display it on my browser?
Thanks in advance
How about:
// ... once get hold of a byte array:
byte[] bytes = (byte[]) entry.getValue();
System.out.println(Base64Utils.encodeToString(bytes));
// ...
Javadoc:
Spring-Base64Utils
An alternative solution using apache IOUtils which matches with your exact requirement.
This is from my Github repo. Where I have the the Entity having:
#Lob
private Byte[] userpicture;
The controller to get image to view:
#GetMapping("appUser/{id}/appUserimage")
public void renderImageFromDB(#PathVariable String id, HttpServletResponse response) throws IOException {
AppUserCommand appUserCommand = appUserService.findCommandById(Long.valueOf(id));
if (appUserCommand.getUserpicture() != null) {
byte[] byteArray = new byte[appUserCommand.getUserpicture().length];
int i = 0;
for (Byte wrappedByte : appUserCommand.getUserpicture()){
byteArray[i++] = wrappedByte; //auto unboxing
}
response.setContentType("image/jpeg");
InputStream is = new ByteArrayInputStream(byteArray);
IOUtils.copy(is, response.getOutputStream());
}
}
And finally the view where the image is displayed:
<div th:if="${appUser.userpicture == null}">
<img th:src="#{/images/defaultuser.jpg}" width="40" height="40" />
Upload </div>
<div th:if="${appUser.userpicture != null}"><img th:src="#{'/appUser/' + ${appUser.id} + '/appUserimage'}" width="40" height="40" />

Alfresco, query with dynamic values

I have a Map with different values:
props = new HashMap<String, Object>();
props.put("cmis:objectTypeId", "D:ruc:PLICO");
props.put("cmis:name", "PLICO_1.pdf");
props.put("cmis:description", "Descr");
props.put("ruc:doc_surname", "Rossi");
props.put("ruc:doc_name", "Mario");
I want to do a query (QueryStatement or other) that dynamically reads this parameters (some of them can be missing) and build QueryStatement.
Does it exist an easy way to generate the query String for QueryStatement? Or do I should iterate my Map to build a String containing all the parameters and values in my query?
My solution, but maybe somebody know how to improve it without dynamically build the query string:
StringBuilder query = new StringBuilder("SELECT * FROM ? where ");
String folder = null;
if (path!=null)
{
folder = findPath(path);
if (folder==null)
{
return null;
}
query.append("IN_FOLDER(?) AND ");
}
ArrayList <String> values = new ArrayList<String>();
Map<String, Object> properties = loadAnnotationAndData(doc);
String objectType = properties.remove(MyEnum.cmis_object_type_id.getValue()).toString();
for (Map.Entry<String, Object> entry : properties.entrySet())
{
System.out.println(entry.getKey() + " - " + entry.getValue());
query.append(entry.getKey() + "=? AND ");
values.add(entry.getValue().toString());
}
query.delete(query.length()-4, query.length());
query.append(" ORDER BY cmis:creationDate");
System.out.println(query.toString());
Session cmisSession = getCmisSession();
QueryStatement qs=
cmisSession.createQueryStatement(query.toString());
int offset = 1;
qs.setType(offset++, objectType);
if (path!=null)
{
qs.setString(offset++, folder);
}
for (int i=0; i<values.size(); i++)
{
System.out.println(values.get(i).toString());
qs.setString(i+offset, values.get(i).toString());
}

Unable to Print matching hashmap keys in Java using Android Studio

I am trying to iterate two hash maps and print the keys that are matching in both of them.Although both of the hash maps have got matching elements it is consistently saying "no match found".
Below posted is my code.
try {
String s = new String(data);
String string = new String(input_bytes);
StringTokenizer stringTokenizer = new StringTokenizer(s);
StringTokenizer input_stringTokenizer = new StringTokenizer(string);
while(stringTokenizer.hasMoreTokens())
{
map.put(stringTokenizer.nextToken(), stringTokenizer.nextToken());
}
while(input_stringTokenizer.hasMoreTokens())
{
input_map.put(input_stringTokenizer.nextToken(),
input_stringTokenizer.nextToken());
}}
catch (Exception e1) {
e1.printStackTrace();
}}
Iterator input1 = map.entrySet().iterator();
Iterator input_2 = input_map.entrySet().iterator();
while (input_2.hasNext() && input1.hasNext()) {
Map.Entry input_val1 = (Map.Entry) input1.next();
Map.Entry input_val2 = (Map.Entry) input_2.next();
String temp = input_val1.getKey().toString().substring(input_val1.getKey().toString().lastIndexOf("\\") + 1);
String temp_2 = input_val2.getKey().toString().substring(input_val2.getKey().toString().lastIndexOf("\\") + 1);
if(temp.equals(temp_2))
{
System.out.println("element matched");
}
else
{
System.out.println("no match found!");
}
}
My input files are "data" and "input_bytes"
The path in these files is the "key" and the hash is the "value" of the hashmap.
For effective matching i have trimmed the path such that it gives me only the element after the last slash.
"temp" variable in the code will print in the following way :
com.example.android.notepad_4.4.2-eng.build.20150616.1901504.apk ﹕
com.facebook.orca_34.0.0.22.2114.apk
com.android.contacts_4.4.2-eng.build.20150616.1901504.apk
com.amazon.venezia_release-13.0003.844.1C_6430003104.apk
com.android.deskclock_3.0.04.apk
com.google.android.apps.photos_1.0.0.943910814.apk
apuslauncher-2.apk
com.android.vending-v5.8.11-80381100-Android-2.3.apk
net.sylark.apkextractor_1.0.54.apk
Here is how my "data" file look like:
C:\Users\rishii\Desktop\input_3\com.amazon.venezia_release-
13.0003.844.1C_6430003104.apk
266796d1b8e2e016753ee3bf1b50e591
C:\Users\rishii\Desktop\input_3\com.android.browser_4.4.2-
eng.build.20150616.1901504.apk
4aa2091b0e21fc655e19d07e2ae20982
C:\Users\rishii\Desktop\input_3\com.android.calculator2_4.4.2-
eng.build.20150616.1901504.apk
85313ccbd39a43952906b70b941d321b
C:\Users\rishii\Desktop\input_3\com.android.calendar_4.4.2-
eng.build.20150616.1901504.apk
3c85cb87f2e134a4157e5f3747e4df1b
Here is my "input_bytes" file looks like:
C:\Users\rishii\Desktop\baal\com.amazon.venezia_release-
13.0003.844.1C_6430003104.apk
266796d1b8e2e016753ee3bf1b50e591
C:\Users\rishii\Desktop\baal\com.android.browser_4.4.2-
eng.build.20150616.1901504.apk
4aa2091b0e21fc655e19d07e2ae20982
C:\Users\rishii\Desktop\baal\com.android.calculator2_4.4.2-
eng.build.20150616.1901504.apk
85313ccbd39a43952906b70b941d321b
C:\Users\rishii\Desktop\baal\com.android.calendar_4.4.2-
eng.build.20150616.1901504.apk
3c85cb87f2e134a4157e5f3747e4df1b
C:\Users\rishii\Desktop\baal\com.android.camera2_2.0.002-
eng.build.ef73894.060315_142358-704.apk
482205cda6991f89fb35311dea668013
If you can see there are some matches in both the files.Any help would be highly appreciated.
Here's a much simpler way to check if they contain the same keys:
public void findSameKeys(Map<String, String> map1, Map<String, String> map2) {
for (String key : map1.keySet()) {
if (map2.containsKey(key)) {
System.out.println("Matching key: " + key);
}
}
}
The containsKey() method is very useful here.

Dynamic data store for ExtJS chart

I am trying to use JSP on server-side to perform a variable number of queries and output the result of all of them as a single block of JSON data for an ExtJS line chart.
The reason the number of queries is variable is because each one represent a different series (a different line) on the line chart, and the number of series is different depending on the line chart that the user selects.
I am using hibernate and my persistence class returns each query data as a: List<Map<String, Object>> (each Map represents one row).
There will always be at least one series (one line on the graph, one query to execute), so the way I was thinking of setting this up is as follows:
1) Have the initial query run and get the first series
2) Run another query to check for any other series that should be on the graph
3) For each "other" series found in the second query run a query that gets the data for that series (same number of rows) and then merge that data into the first List<Map<String, Object>> that was returned in #1 as another column. The query is set-up to order it properly it just needs to be merged at the same index level.
4) Output that List as JSON.
My problem is with #3, I am not sure how to go about the merging the data.
Here's what I have so far:
GenericSelectCommand graphData = new GenericSelectCommand(graphDataQuery);
GenericSelectCommand backSeriesData = new GenericSelectCommand(backSeriesQuery);
List<Map<String, Object>> graphDataList;
List<Map<String, Object>> backSeriesList;
try
{
Persistor myPersistor = new Persistor();
// 1) GET THE INITIAL LINE CHART SERIES
myPersistor.executeTransact(graphData);
graphDataList = graphData.getRows();
// 2) LOOK FOR ANY ADDITIONAL SERIES THAT SHOULD BE ON THE LINE CHART
myPersistor.executeTransact(backSeriesData);
backSeriesList = backSeriesData.getRows();
// 3) FOR EACH ADDITIONAL SERIES FOUND, RUN A QUERY AND APPEND THE DATA TO THE INITIAL LINE CHART SERIES (graphDataList)
for (int i = 0; i < backSeriesList.size(); i++)
{
Map<String, Object> backSeriesBean = backSeriesList.get(i);
// THIS QUERY RETURNS ONE COLUMN OF INT VALUES (THE LINE CHART DATA) WITH THE EXACT SAME NUMBER OF ROWS AS THE INITIAL LINE CHART SERIES (graphDataList)
String backDataQuery = "exec runQuery 'getBackData', '" + backSeriesBean.get("series_id") + "'";
GenericSelectCommand backData = new GenericSelectCommand(backDataQuery);
myPersistor.executeTransact(backData);
List<Map<String, Object>> backDataList = backData.getRows();
// FOR EACH RECORD IN THE BACK DATA (Map<String, Object>)
for (int i = 0; i < backDataList.size(); i++)
{
Map<String, Object> backDataBean = backDataList.get(i);
// HOW DO I ADD IT TO THE RECORD AT THE SAME INDEX LEVEL IN graphDataList (List<Map<String, Object>>)
}
}
}
catch (Throwable e)
{
System.err.println("Error: ");
System.err.println(e.getCause());
}
finally
{
myPersistor.closeSession();
}
// 4) RETURN THE DATA AS JSON NOW THAT IT IS MERGED
for (int i = 0; i < graphDataList.size(); i++)
{
Map<String, Object> graphDataBean = graphDataList.get(i);
out.println(/*JSON FORMAT + graphDataBean.get('data') + JSON FORMAT*/)
}
SOLUTION:
GenericSelectCommand graphData = new GenericSelectCommand(graphDataQuery);
GenericSelectCommand backSeries = new GenericSelectCommand(backSeriesQuery);
List<Map<String, Object>> graphDataList = Collections.emptyList();
List<Map<String, Object>> backSeriesList = Collections.emptyList();
List backDataListArray = new ArrayList();
try
{
// GET THE INITIAL LINE CHART SERIES
Persistor.instance().executeTransact(graphData);
graphDataList = graphData.getRows();
// LOOK FOR ANY ADDITIONAL SERIES THAT SHOULD BE ON THE LINE CHART
Persistor.instance().executeTransact(backSeries);
backSeriesList = backSeries.getRows();
// FOR EACH ADDITIONAL SERIES FOUND, RUN THE QUERY AND ADD IT TO backDataListArray
for (int i = 0; i < backSeriesList.size(); i++)
{
Map<String, Object> backSeriesBean = backSeriesList.get(i);
String backDataQuery = "exec runQuery 'getBackData', " + backSeriesBean.get("series_id");
GenericSelectCommand backData = new GenericSelectCommand(backDataQuery);
Persistor.instance().executeTransact(backData);
List<Map<String, Object>> backDataList = backData.getRows();
backDataListArray.add(backDataList);
}
}
catch (Throwable e)
{
System.err.println("Error: ");
System.err.println(e.getCause());
}
finally
{
Persistor.instance().closeSession();
}
// FOR EACH RECORD IN THE ORIGINAL QUERY, WRITE THE JSON STRING
for (int i = 0; i < graphDataList.size(); i++)
{
StringBuilder backDataString = new StringBuilder();
// BUILD THE BACK DATA STRING (IF THERE IS ANY)
for (int j = 0; j < backDataListArray.size(); j++)
{
List<Map<String, Object>> backDataList = (List<Map<String, Object>>) backDataListArray.get(j);
Map<String, Object> backDataBean = backDataList.get(i);
Map<String, Object> backSeriesBean = backSeriesList.get(j);
backDataString.append(backSeriesBean.get("the_series") + ": " + backDataBean.get("the_count") + ", ");
}
Map<String, Object> graphDataBean = graphDataList.get(i);
out.println("{the_quota: " + graphDataBean.get("the_quota") + ", " + "count_pt_year: " + graphDataBean.get("count_pt_year") + ", " + backDataString + "date_string: '" + graphDataBean.get("date_string") + "'}" + (i + 1 == graphDataList.size() ? "" : "," ));
}
I would not merge the lists. I would just create an outer list for each query and then go through the outer list and return each series list. You can just create the outer list as:
List outerList = new ArrayList();
I would not worry about specifying the types for the outer list as it just makes it more complicated for little benefit.

Categories

Resources