this is my first time to use spring and i don't know about ajax so i just try to make json string in spring controller and send it to javascript and in external js file i want to draw some chart with chart.js but there is problem I think that I do send json string to script file and console.log command show the right json string but I couldn't use my json, for JSON.parse() because
"VM241:1 Uncaught SyntaxError: Unexpected token ''', "'" is not valid JSON at JSON.parse ()"
here is my controller code and customizeSerializer class
package com.datacampus.biohealth2.serializer;
import com.datacampus.biohealth2.dto.PerDayNutritionDto;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
public class PerNutritionDtoSerializer extends JsonSerializer<PerDayNutritionDto> {
@Override
public void serialize(PerDayNutritionDto perDayNutritionDto, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider)throws IOException, JsonProcessingException {
jsonGenerator.writeStartObject();
jsonGenerator.writeFieldName("kcal");
jsonGenerator.writeString(String.valueOf(perDayNutritionDto.getKcal()));
jsonGenerator.writeFieldName("protein");
jsonGenerator.writeString(String.valueOf(perDayNutritionDto.getProtein()));
jsonGenerator.writeFieldName("Sugar");
jsonGenerator.writeString(String.valueOf(perDayNutritionDto.getSugar()));
jsonGenerator.writeFieldName("Sodium");
jsonGenerator.writeString(String.valueOf(perDayNutritionDto.getSodium()));
jsonGenerator.writeFieldName("Saturated_fat");
jsonGenerator.writeString(String.valueOf(perDayNutritionDto.getSaturatedFat()));
jsonGenerator.writeFieldName("Caffeine");
jsonGenerator.writeString(String.valueOf(perDayNutritionDto.getCaffeine()));
jsonGenerator.writeFieldName("drink_kcal");
jsonGenerator.writeString(String.valueOf(perDayNutritionDto.getDrink_kcal()));
jsonGenerator.writeFieldName("drink_protein");
jsonGenerator.writeString(String.valueOf(perDayNutritionDto.getDrink_protein()));
jsonGenerator.writeFieldName("drink_sugar");
jsonGenerator.writeString(String.valueOf(perDayNutritionDto.getDrink_sugar()));
jsonGenerator.writeFieldName("drink_Sodium");
jsonGenerator.writeString(String.valueOf(perDayNutritionDto.getDrink_Sodium()));
jsonGenerator.writeFieldName("drink_Caffeine");
jsonGenerator.writeString(String.valueOf(perDayNutritionDto.getDrink_caffeine()));
jsonGenerator.writeFieldName("drink_saturated_fat");
jsonGenerator.writeString(String.valueOf(perDayNutritionDto.getDrink_saturatedFat()));
jsonGenerator.writeEndObject();
}
}
and this is my CustomSerializer for make it at module
package com.datacampus.biohealth2.serializer;
import com.datacampus.biohealth2.dto.PerDayNutritionDto;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
public class CustomSerializer {
public static ObjectMapper getCustomObjectMapper(){
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(PerDayNutritionDto.class,new PerNutritionDtoSerializer());
objectMapper.registerModule(simpleModule);
return objectMapper;
}
}
and this is my controller to send json
@GetMapping("/show")
public String showHealthInformation(@AuthenticationPrincipal UserDetails userDetails, Model model) throws JsonProcessingException {
String userEmail = userDetails.getUsername();
Member member = memberRepository.findByEmail(userEmail);
HealthInformation healthInformation = healthInformationRepository.findByMember_Id(member.getId());
model.addAttribute("userName",member.getName());
model.addAttribute("user_weight",healthInformation.getWeight());
model.addAttribute("user_height",healthInformation.getHeight());
model.addAttribute("user_gender",healthInformation.getGender());
model.addAttribute("user_activity",healthInformation.getActivityType());
model.addAttribute("user_age",healthInformation.getAge());
PerDayNutrition perDayNutrition = perDayNutritionRepository
.findPerDayNutritionByHealthInformation_Id(healthInformation.getId());
PerDayNutritionDto perDayNutritionDto = perDayNutritionService.getPerDayNutritionDto(perDayNutrition);
ObjectMapper objectMapper = CustomSerializer.getCustomObjectMapper();
String perDayNutritionJson = objectMapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(perDayNutritionDto);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("\'");
stringBuilder.append(perDayNutritionJson);
stringBuilder.append("\'");
perDayNutritionJson = stringBuilder.toString();
model.addAttribute("perDayNutritionJson",perDayNutritionJson);
System.out.println(perDayNutritionJson);
return "healthInformation/showHealthInformation";
}
and this is my html using thymeleaf
<script th:inline="javascript" type="text/javascript">
/*<![CDATA[*/
let perDayNutritionJson = [[${perDayNutritionJson}]];
alert(perDayNutritionJson);
/*]]>*/
</script>
<script src="/vendor/jquery/jquery.min.js"></script>
<script src="/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- Core plugin JavaScript-->
<script src="/vendor/jquery-easing/jquery.easing.min.js"></script>
<!-- Custom scripts for all pages-->
<script src="/js/sb-admin-2.min.js"></script>
<!-- Page level plugins -->
<script src="/vendor/chart.js/Chart.min.js"></script>
<!-- Page level custom scripts -->
<script src="/js/demo/chart-area-demo.js"></script>
<script src="/js/demo/chart-pie-demo.js"></script>
<script src="/js/demo/chart-bar-demo.js"></script>
and this is chart-bar-demo.js file to draw bar chart with the json string that I sent at controller and this chart.js is not done yet
// Set new default font family and font color to mimic Bootstrap's default styling
Chart.defaults.global.defaultFontFamily = 'Nunito', '-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
Chart.defaults.global.defaultFontColor = '#858796';
function number_format(number, decimals, dec_point, thousands_sep) {
// * example: number_format(1234.56, 2, ',', ' ');
// * return: '1 234,56'
number = (number + '').replace(',', '').replace(' ', '');
var n = !isFinite(+number) ? 0 : +number,
prec = !isFinite(+decimals) ? 0 : Math.abs(decimals),
sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
dec = (typeof dec_point === 'undefined') ? '.' : dec_point,
s = '',
toFixedFix = function(n, prec) {
var k = Math.pow(10, prec);
return '' + Math.round(n * k) / k;
};
// Fix for IE parseFloat(0.55).toFixed(0) = 0;
s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
if (s[0].length > 3) {
s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep);
}
if ((s[1] || '').length < prec) {
s[1] = s[1] || '';
s[1] += new Array(prec - s[1].length + 1).join('0');
}
return s.join(dec);
}
// Bar Chart Example
console.log(perDayNutritionJson);
perDayNutritionJson = perDayNutritionJson[0][0];
// Preserve newlines, etc. - use valid JSON
perDayNutritionJson = perDayNutritionJson.replace(/\\n/g, "\\n")
.replace(/\\'/g, "\\'")
.replace(/\\"/g, '\\"')
.replace(/\\&/g, "\\&")
.replace(/\\r/g, "\\r")
.replace(/\\t/g, "\\t")
.replace(/\\b/g, "\\b")
.replace(/\\f/g, "\\f");
// Remove non-printable and other non-valid JSON characters
perDayNutritionJson = perDayNutritionJson.replace(/[\u0000-\u0019]+/g,"");
var perDay = JSON.parse(perDayNutritionJson);
console.log(perDay)
var ctx = document.getElementById("myBarChart");
var myBarChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["kcal", "Sugar", "Saturated_fat", "Caffeine", "Protein", "Sodium"],
datasets: [{
label: "영양성분 일일 권장량",
backgroundColor: "#4e73df",
hoverBackgroundColor: "#2e59d9",
borderColor: "#4e73df",
data: [ perDay.kcal,perDay.protein,perDay.Sugar,perDay.Sodium,perDay.Saturated_fat,perDay.Caffeine],
}],
},
options: {
maintainAspectRatio: false,
layout: {
padding: {
left: 10,
right: 25,
top: 25,
bottom: 0
}
},
scales: {
xAxes: [{
time: {
unit: 'month'
},
gridLines: {
display: false,
drawBorder: false
},
ticks: {
maxTicksLimit: 6
},
maxBarThickness: 25,
}],
yAxes: [{
ticks: {
min: 0,
max: 400,
maxTicksLimit: 5,
padding: 10,
// Include a dollar sign in the ticks
callback: function(value, index, values) {
return number_format(value);
}
},
gridLines: {
color: "rgb(234, 236, 244)",
zeroLineColor: "rgb(234, 236, 244)",
drawBorder: false,
borderDash: [2],
zeroLineBorderDash: [2]
}
}],
},
legend: {
display: false
},
tooltips: {
titleMarginBottom: 10,
titleFontColor: '#6e707e',
titleFontSize: 14,
backgroundColor: "rgb(255,255,255)",
bodyFontColor: "#858796",
borderColor: '#dddfeb',
borderWidth: 1,
xPadding: 15,
yPadding: 15,
displayColors: false,
caretPadding: 10,
callbacks: {
label: function(tooltipItem, chart) {
var datasetLabel = chart.datasets[tooltipItem.datasetIndex].label || '';
return datasetLabel + number_format(tooltipItem.yLabel);
}
}
},
}
});
in this code i just wanna check console.log(perDay) this first but there is always error and
// Bar Chart Example
console.log(perDayNutritionJson);
perDayNutritionJson = perDayNutritionJson[0][0];
// Preserve newlines, etc. - use valid JSON
perDayNutritionJson = perDayNutritionJson.replace(/\\n/g, "\\n")
.replace(/\\'/g, "\\'")
.replace(/\\"/g, '\\"')
.replace(/\\&/g, "\\&")
.replace(/\\r/g, "\\r")
.replace(/\\t/g, "\\t")
.replace(/\\b/g, "\\b")
.replace(/\\f/g, "\\f");
// Remove non-printable and other non-valid JSON characters
perDayNutritionJson = perDayNutritionJson.replace(/[\u0000-\u0019]+/g,"");
var perDay = JSON.parse(perDayNutritionJson);
console.log(perDay)
I think at this part there is a problem but I don't know exactly what it is.