I am beginner for Spring Boot and I save multiple files in my MySQL database which seems like below and it's working fine and now I want to retrieve saved files
I do not understand how can I read blob data and how to convert into a URL for showing users.
Controller
#RequestMapping(value = "/getUser", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
#ResponseBody
public DBFile getUserById(#RequestBody DBFile dBFile ) {
DBFile record = employeeRepository.findById(dBFile.getId());
return record;
}
Repository
public interface MultipartRepository1 extends JpaRepository<DBFile, Integer{}
DTO
#Entity
#Table(name = "files")
public class DBFile {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
private String id;
private String file_name;
private String file_type;
#Lob
private byte[] data;
public DBFile() {
}
public DBFile(String file_name, String file_type, byte[] data) {
this.file_name = file_name;
this.file_type = file_type;
this.data = data;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getFile_name() {
return file_name;
}
public void setFile_name(String file_name) {
this.file_name = file_name;
}
public String getFile_type() {
return file_type;
}
public void setFile_type(String file_type) {
this.file_type = file_type;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
}
Table
673e148e-a209-45c8-914c-7016dd59542f BLOB home_beach.jpg image/jpeg
a55777bc-5fda-41a7-a589-3731ae418262 BLOB beach-houses.jpg image/jpeg
ce3f502c-f780-4a7d-a7d1-e678adfa367d BLOB theahotel_logo.png image/png
Spring boot will automatically return your blob field as a base64 string e.g.
{"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAABfAAAAXwBsrqMZwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAADdSURBVEiJtZTLCoUgEIZNaG90EfIFhXxTW6WbfJn/LA5xzOpUMg7MZmb4PvAyFWMMrGDwp4NSSqa1zpLgLqWU8N4DAIwxt/NJ/h9QSiGEAACw1kIIQSeI4fM8o2mat/BrQQxflgVd1+XAzwUpvO/7XPhRQAzfC2K4c44C/hOk8GEYKOBfQQz33lPCwdq2hXMOpYLXdc04f7wxsmK3CohezvGShRCw1gIA1nXFOI60goKSfaGA5Fgklpw3CCXXzVSilKIVpJIQQo7kfij+J9M00Qs2idb69RFVm6VUfACZhb1lipibXgAAAABJRU5ErkJggg=="}
You can return just that field from an endpoint. Then convert that to an image on the client application.
Related
I am using SpringBoot and trying to deserialize JSON like:
{
"userId": "Dave",
"queryResults": {
"id": "ABC",
"carData": {.....},
"carId": "Honda",
"status": 0,
"model": "X"
}
}
, into MyRequestModel clas:
public class MyRequestModel {
private String userId;
private String: queryResults;
}
, that is received as #RequestBody parameter in my #PostMapping method that looks like:
#PostMapping
public String postDate(#RequestBody MyRequestModel data) {
...
return "posted";
}
The above queryResults field is supposed to be stored as a CLOB in a database.
Problem I am having is that if I send this JSON to hit my endpoint (PostMapping) method, it cannot deserialize it into MyRequestModel and I get this error:
Cannot deserialize instance of java.lang.String out of START_OBJECT token
at [Source: (PushbackInputStream); line: 3, column: 18] (through reference chain: MyRequestModel["queryResults"])]
I guess the real answer to your question is: if you NEED the queryResults property to be a String, then implement a custom deserializer.
If not, then, use one of the alternatives that Jonatan and Montaser proposed in the other answers.
Implementing a custom deserializer within Spring Boot is fairly straightforward, since Jackson is its default serializer / deserializer and it provides a easy way to write our own deserializer.
First, create a class that implements the StdDeserializer<T>:
MyRequestModelDeserializer.java
public class MyRequestModelDeserializer extends StdDeserializer<MyRequestModel> {
public MyRequestModelDeserializer() {
this(null);
}
public MyRequestModelDeserializer(Class<?> vc) {
super(vc);
}
#Override
public MyRequestModel deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = p.getCodec().readTree(p);
String userId = node.get("userId").asText();
String queryResults = node.get("queryResults").toString();
MyRequestModel model = new MyRequestModel();
model.setQueryResults(queryResults);
model.setUserId(userId);
return model;
}
}
Second, mark your class to be deserialized using your custom deserializer by using the #JsonDeserialize annotation:
MyRequestModel.java
#JsonDeserialize(using = MyRequestModelDeserializer.class)
public class MyRequestModel {
private String userId;
private String queryResults;
}
It's done.
queryResults is a String on Java side but it is an Object on JSON side.
You will be able to deserialize it if you send it in as a String:
{
"userId": "Dave",
"queryResults": "foo"
}
or if you create classes that maps to the fields:
public class MyRequestModel {
private String userId;
private QueryResults queryResults;
}
public class QueryResults {
private String id;
private CarData carData;
private String carId;
private Integer status;
private String model;
}
or if you serialize it into something generic (not recommended):
public class MyRequestModel {
private String userId;
private Object queryResults;
}
public class MyRequestModel {
private String userId;
private Map<String, Object> queryResults;
}
public class MyRequestModel {
private String userId;
private JsonNode queryResults;
}
You have two options to deserialize this request:-
change the type of queryResults to Map<String, Object>, it will accepts everything as an object of key and value. (Not recommended)
public class MyRequestModel {
private String userId;
private Map<String, Object> queryResults;
}
You have to create a class that wraps the results of queryResults as an object.
class QueryResult {
private String id;
private Map<String, Object> carData;
private String carId;
private Integer status;
private String model;
public QueryResult() {}
public QueryResult(String id, Map<String, Object> carData, String carId, Integer status, String model) {
this.id = id;
this.carData = carData;
this.carId = carId;
this.status = status;
this.model = model;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Map<String, Object> getCarData() {
return carData;
}
public void setCarData(Map<String, Object> carData) {
this.carData = carData;
}
public String getCarId() {
return carId;
}
public void setCarId(String carId) {
this.carId = carId;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
and make the type of queryResult as shown:-
public class MyRequestModel {
private String userId;
private QueryResult queryResults;
}
How can I save Raw Json as String in the MsSql db with the POST request - using Jackson ObjectMapper to convert the string to Json but not able to change raw json into string?
{
"id": 1,
"someName":"someName",
"json": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossTerm": "Standard Generalized Markup Language"
}
},
"anotherjson":{
"name":"someone",
"age": 121
},
"somedate":"03-11-2019.00:00:00"
}
How can I save this save json as integer, varchar, string, string, date column in the db?
1,someName, "{"title": "example glossary","GlossDiv": {"title": "S","GlossTerm": "Standard Generalized Markup Language"}","{"name":"someone","age": 121}", 03-11-2019.00:00:00.
** Update **
For simplicity here is the simple json
{
"id":1,
"jsonObjectHolder":{
"name": "Name",
"age" : 404
}}
Controller:
#PostMapping("/postJson")
public void postJson(#RequestBody TryJson tryJson) {
tryJsonService.postJson(tryJson);
}
Service:
public void postJson(TryJson tryJson) {
tryJsonRepository.save(tryJson);
}
Repo:
public interface TryJsonRepository extends CrudRepository<TryJson, Integer> {
}
Model:
#Entity
#Table(name = "TryJson")
public class TryJson {
#Id
#Column(name = "id")
private Integer id;
#JsonIgnore
#Column(name = "json_column")
private String jsonColumn;
#Transient
private JsonNode jsonObjectHolder;
public TryJson() {
}
public TryJson(Integer id, String jsonColumn) {
this.id = id;
this.jsonColumn = jsonColumn;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public JsonNode getJsonObjectHolder() {
return jsonObjectHolder;
}
public void setJsonObjectHolder(JsonNode jsonObjectHolder) {
this.jsonObjectHolder = jsonObjectHolder;
}
public String getJsonColumn() {
return this.jsonObjectHolder.toString();
}
public void setJsonColumn(String jsonColumn) throws IOException {
ObjectMapper mapper = new ObjectMapper();
this.jsonObjectHolder = mapper.readTree(jsonColumn);
}
#Override
public String toString() {
return String.format("TryJson [Id=%s, JsonColumn=%s, jsonObjectHolder=%s]", id, jsonColumn, jsonObjectHolder);
}
}
http://localhost:8080/api/postJson
ID JSON_COLUMN
1 null
Not sure what I am missing here. I do get jsonObjectHolder populated during the debugging but then still I get NULL
TryJson [Id=1, JsonColumn=null, jsonObjectHolder={"name":"Name","age":404}]
Update 2
I am getting null pointer exception.
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: Exception occurred inside getter of com.example.tryjson.tryjson.model.TryJson.jsonColumn; nested exception is org.hibernate.PropertyAccessException: Exception occurred inside getter of com.example.tryjson.tryjson.model.TryJson.jsonColumn] with root cause
java.lang.NullPointerException: null
at com.example.tryjson.tryjson.model.TryJson.getJsonColumn(TryJson.java:52) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_192]
Here is my new model
#Entity
#Table(name = "TryJson")
public class TryJson {
private Integer id;
#Transient
private JsonNode jsonObjectHolder;
public TryJson() {
}
public TryJson(Integer id, JsonNode jsonObjectHolder) {
this.id = id;
this.jsonObjectHolder = jsonObjectHolder;
}
#Id
#Column(name = "id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Transient
public JsonNode getJsonObjectHolder() {
return jsonObjectHolder;
}
public void setJsonObjectHolder(JsonNode jsonObjectHolder) {
this.jsonObjectHolder = jsonObjectHolder;
}
#Column(name = "json_column")
public String getJsonColumn() {
return this.jsonObjectHolder.toString();
}
public void setJsonColumn(String jsonColumn) throws IOException {
ObjectMapper mapper = new ObjectMapper();
this.jsonObjectHolder = mapper.readTree(jsonColumn);
}
}
You could define a JsonNode json property to hold the part you want to persist as text, then mark it as #Transient so JPA does not try to store it on database. However, jackson should be able to translate it back and forward to Json.
Then you can code getter/setter for JPA, so you translate from JsonNode to String back and forward. You define a getter getJsonString that translate JsonNode json to String. That one can be mapped to a table column, like 'json_string', then you define a setter where you receive the String from JPA and parse it to JsonNode that will be avaialable for jackson.
Do not forget to add #JsonIgnore to getJsonString so Jackson does not try to translate to json as jsonString.
#Entity
#Table(name = "request")
public class Request {
private Long id;
private String someName;
#Transient
private JsonNode json;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
#Column(name ="someName")
public String getSomeName() {
return name;
}
public void setSomeName(String name) {
this.name = name;
}
public void setId(Long id) {
this.id = id;
}
// Getter and setter for name
#Transient // This is for Jackson
public JsonNode getJson() {
return json;
}
public void setJson(JsonNode json) {
this.json = json;
}
#Column(name ="jsonString")
public String getJsonString() { // This is for JPA
return this.json.toString();
}
public void setJsonString(String jsonString) { // This is for JPA
// parse from String to JsonNode object
ObjectMapper mapper = new ObjectMapper();
try {
this.json = mapper.readTree(jsonString);
} catch (Exception e) {
e.printStackTrace();
}
}
}
UPDATE:
If you mark jsonColumn with #Column spring will use reflection to pull out the data with default initialization null, getJsonColumn translation will never be executed:
#JsonIgnore
#Column(name = "json_column")
private String jsonColumn;
You do not need a jsonColumn, just make sure you mark your setters with #Column, so spring uses gettets/setters to persist to database, when persisting, jpa will execute getJsonColumn, when reading, jpa will execute setJsonColumn and jsonNode will be translated back and forward to string:
#Entity
#Table(name = "TryJson") public class TryJson {
private Integer id;
#Transient
private JsonNode jsonObjectHolder;
public TryJson() {
}
public TryJson(Integer id, String jsonColumn) {
this.id = id;
this.jsonObjectHolder = // use mapper to create the jsonObject;
}
#Id
#Column(name = "id")
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public JsonNode getJsonObjectHolder() {
return jsonObjectHolder;
}
public void setJsonObjectHolder(JsonNode jsonObjectHolder) {
this.jsonObjectHolder = jsonObjectHolder;
}
#Column(name = "json_column")
public String getJsonColumn() {
return this.jsonObjectHolder.toString();
}
public void setJsonColumn(String jsonColumn) throws IOException {
ObjectMapper mapper = new ObjectMapper();
this.jsonObjectHolder = mapper.readTree(jsonColumn);
}
#Override
public String toString() {
return String.format("TryJson [Id=%s, JsonColumn=%s, jsonObjectHolder=%s]", id, jsonColumn, jsonObjectHolder);
}
}
ObjectMapper mapper = new ObjectMapper();
TypeReference<List<User>> typeReference = new TypeReference<List<Your_Entity>>() {};
InputStream inputStream = TypeReference.class.getResourceAsStream("/bootstrap.json");
try {
List<Your_Entity> users = mapper.readValue(inputStream, typeReference);
log.info("Saving users...");
userService.saveAllUsers(users);
log.info(users.size() + " Users Saved...");
} catch (IOException e) {
log.error("Unable to save users: " + e.getMessage());
}
One of my api response is as below -
{
"statusCode": 422,
"error": "Unprocessable Entity",
"message": "Bad data received",
"err_data": {
"email": {
"location": "body",
"param": "email",
"value": false,
"msg": "Please provide valid e-mail address"
}
}
}
So, in below response.asString() represents above response body.
ApiResponse response = new Gson().fromJson(response.asString(), ApiResponse.class);
ApiResponse.class is my model which is as below:
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({ "statusCode", "message" })
public class ApiResponse implements Serializable {
private static final long serialVersionUID = 1L;
#JsonProperty("message")
private String message;
#JsonProperty("statusCode")
private int statusCode;
#JsonProperty("err_data")
private List<String> errData = new ArrayList<>();
#JsonProperty("email")
private List<String> email = new ArrayList<>();
#JsonProperty("msg")
private String msg;
/**
* No args constructor for use in serialization
*/
public ApiResponse() {
}
/**
* #param message
*/
public ApiResponse(int statusCode, String message, List<String> errData, List<String> email, String msg) {
this.message = message;
this.statusCode = statusCode;
this.errData = errData;
this.email = email;
this.msg = msg;
}
#JsonProperty("statusCode")
public int getStatusCode() {
return statusCode;
}
#JsonProperty("statusCode")
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
#JsonProperty("message")
public String getMessage() {
return message;
}
#JsonProperty("message")
public void setMessage(String message) {
this.message = message;
}
#JsonProperty("err_data")
public List<String> getErrData() {
return errData;
}
#JsonProperty("err_data")
public void setErrData(List<String> errData) {
this.errData = errData;
}
#JsonProperty("email")
public List<String> getEmail() {
return email;
}
#JsonProperty("email")
public void setEmail(List<String> email) {
this.email = email;
}
#JsonProperty("msg")
public String getMsg() {
return msg;
}
#JsonProperty("msg")
public void setMsg(String msg) {
this.msg = msg;
}
}
When I am trying to get msg under "email":{}, it is returning null.
ApiResponse apiResponse = new Gson().fromJson(response.asString(), ApiResponse.class);
// this prints correct value
System.out.println(apiResponse.getMessage());
// this prints correct value
System.out.println(apiResponse.getStatusCode());
// this prints empty string array => []
System.out.println(apiResponse.getErrData());
// this also prints empty string array => []
System.out.println(apiResponse.getEmail());
// this prints null
System.out.println(apiResponse.getMsg());
I am new to fasterxml.jackson lib and not sure what I am missing.
To get msg value, what changes I'll have to do in model class above. Thank you very much in advance.
This is where your code is incorrect :
#JsonProperty("err_data")
private List<String> errData = new ArrayList<>();
#JsonProperty("email")
private List<String> email = new ArrayList<>();
Both email and errData is not a List, they are a separate Object. Just like the ApiResponse.java, you need to create POJO for both objects. For example :
public class Email {
private String location;
private String param;
private String value;
private String msg;
// define getter and setter
}
and
public class ErrData {
private Email email;
// define getter and setter
}
Then use the new class as the object type.
#JsonProperty("err_data")
private ErrData errData;
// email is already inside ErrData, you don't need to define them here
Finally to access your msg :
errData.getEmail().getMsg();
Hope this is clear enough. Good luck!
I am a running a project with SpringBoot. In this project I am calling an external Rest Service. I have modeled the response items into bean.
But when I get the response back the data are not serialised into the beans.
I guess there must be some configuration missing but I cannot find what.
I have added onfiguration spring-boot-starter-test to the configuration of Maven:
The rest client:
#RunWith(SpringRunner.class)
#SpringBootTest
public class RestClientTest {
#Autowired
private RestTemplateBuilder restTemplate;
#Test
public void sayHello() {
System.out.println("Hello");
assert(true);
}
#Test
public void testGetEmployee() {
RestTemplate template = restTemplate.build();;
HttpHeaders headers = new HttpHeaders();
List<MediaType> types = new ArrayList<MediaType>();
types.add(MediaType.APPLICATION_JSON);
types.add(MediaType.APPLICATION_XML);
headers.setAccept(types);
headers.set("Authorization", "Bearer gWRdGO7sUhAXHXBnjlBCtTP");
HttpEntity<Items> entity = new HttpEntity<Items>(headers);
String uri = "https://mytest.com/employees";
//ResponseEntity<String> rec = template.exchange(uri, HttpMethod.GET, entity, String.class);
//System.out.println("Received: " + rec);
ResponseEntity<Items> rec = template.exchange(uri, HttpMethod.GET, entity, Items.class);
System.out.println("Received: " + rec);
}
}
When I inspect the elements of the response it, I get a list, all the items are with null values
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public class Item implements Serializable {
#JsonProperty
private String id;
#JsonProperty
private String name;
#JsonProperty
private String email;
#JsonProperty
private String phone;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
#JsonFormat(shape = JsonFormat.Shape.OBJECT)
public class Items implements Serializable {
#JsonProperty
private List<Item> items = new ArrayList<Item>();
public List<Item> getItems() {
return items;
}
}
Do you see what I am missing here?
The response is like this:
{
"items": [
{
"item": {
"id": 0,
"name": "string",
"email": "string",
"phone": "string",
Do you see what I am missing here?
Thanks
Gilles
The way you have implemented will try to deserialize data into Items class. But it doesn't have the required properties to deserialize. When you need to get a list of data through rest template exchange, you can get them as follows.
Get data as an array and convert it into arrayList.
Item[] itemArray = template.exchange(uri, HttpMethod.GET, entity, Item[].class).getBody();
List<Item> itemList = Arrays,asList(itemArray);
or
Use ParameterizedTypeReference to get data as a list
ResponseEntity<List<Item>> itemList = template.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<List<Item>>() {});
List<Item> itemList = template.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<List<Item>>() {}).getBody(); // access list directly
You might need to add this to your ObjectMapper:
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
And on your entity add #JsonRootName("item")
I have a REST service defined in Spring as follows:
#RequestMapping(value = "/create", method = RequestMethod.POST)
#ResponseBody
public ResponseEntity<String> addArticle(#RequestBody Article article){
try{
articleService.addArticle(article.getTitle(),
article.getContent(),
article.getTags(),
article.getPublishStatus(),
article.getCompanyId(),
article.getCategory());
return new ResponseEntity<String>(HttpStatus.OK);
} catch (Exception e){
e.printStackTrace();
return new ResponseEntity<String>(e.getMessage(), HttpStatus.OK);
}
}
And my article is defined as follows:
public class Article {
private int id;
private String title;
private String content;
private String smsContent;
public String getSmsContent()
{
return smsContent;
}
public void setSmsContent(String smsContent)
{
this.smsContent = smsContent;
}
private String[] tags;
private int companyId;
private String category;
public String getCategory(){
return category;
}
public void setCategory(String category){
this.category = category;
}
private byte publishStatus;
public String getTitle(){
return title;
}
public void setTitle(String title){
this.title = title;
}
public String getContent(){
return content;
}
public void setContent(String content){
this.content = content;
}
public String[] getTags(){
return tags;
}
public void setTags(String[] tags){
this.tags = tags;
}
public int getCompanyId(){
return companyId;
}
public void setCompanyId(int companyId){
this.companyId = companyId;
}
public byte getPublishStatus(){
return publishStatus;
}
public void setPublishStatus(byte publishStatus){
this.publishStatus = publishStatus;
}
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
}
How do I call this service using Angular? I tried following code:
function createArticle(name, companyId, title, content, tags, category) {
var request = $http({
method : 'POST',
url : '/inbound/api/article/create.json',
headers : {
'Content-Type' : 'application/x-www-form-urlencoded'
},
transformRequest : function(obj) {
var str = [];
for ( var p in obj)
str.push(encodeURIComponent(p) + "="
+ encodeURIComponent(obj[p]));
return str.join("&");
},
data : {
title : title,
content : content,
tags : tags,
companyId : companyId,
category: category
}
});
I am getting error 415 (Unsupported Media Type). Any ideas?
Since you're working with JSON, you need to set your form and handler accordingly.
REST handler
#RequestMapping(value = "/create", method = RequestMethod.POST, consumes = "application/json")
Angular
headers : {
'Content-Type' : 'application/json'
},
First
you have:
#RequestMapping(value = "/create", method = RequestMethod.POST)
just /create
Second
You have:
url : '/inbound/api/article/create.json',
Proceed to remove the .json that's the problem
Third
Be sure to indicate for the ajax event, the data you are sending is in JSON