Lets say we have two springboot applcation i.e. producerspringboot and consumerspringboot.
We will try to have the proto class as a data transfer object between them.
we are using to use the same our tutorial.proto given below. We had already created the stub for below proto files in our previous example
http://siddharathadhumale.blogspot.com/2021/10/protocolbuffer-and-its-uses-in-java-and.html
1- tutorial.proto
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | syntax = "proto2"; package tutorial; option java_multiple_files = true; option java_package = "com.example.tutorial.protos"; option java_outer_classname = "AddressBookProtos"; message Person { optional string name = 1; optional int32 id = 2; optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { optional string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phones = 4; } message AddressBook { repeated Person people = 1; } |
Now lets create our first Springboot application names as consumberspringboot application. Please follow the below step religiously to create it.
Note:- We are using STS as an IDE.
Now lets add the protobuf dependencies in pom.xml and also the resttemplate dependencies as we are going to send the proto data from this springboot to another springboot application.
Add following in pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.19.0</version> </dependency> <plugin> <groupId>com.github.os72</groupId> <artifactId>protoc-jar-maven-plugin</artifactId> <version>3.11.4</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>run</goal> </goals> <configuration> <protocVersion>3.19.0</protocVersion> <inputDirectories> <include>src/main/protobuf</include> </inputDirectories> <outputDirectory>src/main/generated</outputDirectory> </configuration> </execution> </executions> </plugin> |
Now add following method in controller that will perform CRUD operation. Modify your class given belwo
1- Add RestTemplate in main class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | package com.siddhu; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication public class ConsumerspringbootApplication { public static void main(String[] args) { SpringApplication.run(ConsumerspringbootApplication.class, args); } @Bean public RestTemplate getRestTemplate() { return new RestTemplate(); } } 2- Create controller package com.siddhu; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import com.example.tutorial.protos.Person; import com.example.tutorial.protos.PersonModel; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.databind.annotation.JsonSerialize; @RestController public class ConsumeWebController { @Autowired RestTemplate restTemplate; @JsonSerialize(using = ProtobufSerializer.class) private Person.Builder builder = Person.newBuilder(); // GET Method - To Select the data. @RequestMapping(value = "/person") public String getPerson() { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); HttpEntity<String> entity = new HttpEntity<String>(headers); return restTemplate.exchange("http://localhost:8081/person", HttpMethod.GET, entity, String.class).getBody(); } // POST Method :- To insert the data. @RequestMapping(value = "/person", method = RequestMethod.POST) public String createPerson(@RequestBody PersonModel personModel) { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); HttpEntity<PersonModel> entity = new HttpEntity<PersonModel>(personModel,headers); return restTemplate.exchange("http://localhost:8081/person", HttpMethod.POST, entity, String.class).getBody(); } // PUT Method :- To update the data. @RequestMapping(value = "/person/{id}", method = RequestMethod.PUT) public String updatePerson(@PathVariable("id") String id, @RequestBody PersonModel personModel) { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); HttpEntity<PersonModel> entity = new HttpEntity<PersonModel>(personModel,headers); return restTemplate.exchange("http://localhost:8081/person/"+id, HttpMethod.PUT, entity, String.class).getBody(); } // DELETE Method :- To delete the data. @RequestMapping(value = "/person/{id}", method = RequestMethod.DELETE) public String deletePerson(@PathVariable("id") String id) { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); HttpEntity<PersonModel> entity = new HttpEntity<PersonModel>(headers); return restTemplate.exchange("http://localhost:8081/person/"+id, HttpMethod.DELETE, entity, String.class).getBody(); } } |
3- Add all the files that we create in using proto files in our project.
As you can see we are making a call using rest template on port 8081. This is our second springboot application called as producerspringboot.
In this producerspringboot we will return the request as per the CRUD opeation request from
Lets First we will try to send the response from our consumerspringboot application and check if we are getting values set in our proto generated files.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | package com.siddhu; import java.util.Arrays; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import com.example.tutorial.protos.AddressBook; import com.example.tutorial.protos.Person; import com.example.tutorial.protos.Person.PhoneNumber; import com.example.tutorial.protos.Person.PhoneType; import com.example.tutorial.protos.PersonModel; @RestController public class ConsumeWebController { @Autowired RestTemplate restTemplate; // GET Method - To Select the data. @RequestMapping(value = "/person") public String getPerson() { return getData().toString(); //return restTemplate.exchange("http://localhost:8080/person", HttpMethod.GET, entity, String.class).getBody(); } // POST Method :- To insert the data. @RequestMapping(value = "/person", method = RequestMethod.POST) public String createPerson(@RequestBody PersonModel personModel) { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); HttpEntity<PersonModel> entity = new HttpEntity<PersonModel>(personModel,headers); Person.Builder builder = getData(); builder.setId(entity.getBody().getId()); builder.setName(entity.getBody().getName()); return builder.toString(); //return restTemplate.exchange("http://localhost:8080/person", HttpMethod.POST, entity, String.class).getBody(); } // PUT Method :- To update the data. @RequestMapping(value = "/person/{id}", method = RequestMethod.PUT) public String updatePerson(@PathVariable("id") String id, @RequestBody PersonModel personModel) { HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); HttpEntity<PersonModel> entity = new HttpEntity<PersonModel>(personModel,headers); Person.Builder builder = getData(); builder.setName(entity.getBody().getName()); return builder.toString(); //return restTemplate.exchange("http://localhost:8080/person/"+id, HttpMethod.PUT, entity, String.class).getBody(); } // DELETE Method :- To delete the data. @RequestMapping(value = "/person/{id}", method = RequestMethod.DELETE) public String deletePerson(@PathVariable("id") String id) { Person.Builder builder = getData(); builder.clearId(); return builder.toString(); //return restTemplate.exchange("http://localhost:8080/person/"+id, HttpMethod.DELETE, entity, String.class).getBody(); } //Data preparation Start[ private Person.Builder getData() { Person.Builder builder = Person.newBuilder(); builder.setName("siddhu"); builder.setId(126); builder.setEmail("shdhumale@gmail.com"); System.out.println("builder.toString():-"+builder.toString()); PhoneNumber.Builder PhoneNumberBuilder = PhoneNumber.newBuilder(); PhoneNumberBuilder.setNumber("1111111"); PhoneNumberBuilder.setType(PhoneType.HOME); //builder.setPhones(0, PhoneNumberBuilder); PhoneNumber.Builder PhoneNumberBuilder1 = PhoneNumber.newBuilder(); PhoneNumberBuilder1.setNumber("222222222"); PhoneNumberBuilder1.setType(PhoneType.MOBILE); //builder.setPhones(1, PhoneNumberBuilder1); builder.addPhones(PhoneNumberBuilder).addPhones(PhoneNumberBuilder1); System.out.println("builder after adding PhoneNumberBuilder1.toString():-"+builder.toString()); AddressBook.Builder AddressBookBuilder = AddressBook.newBuilder(); //AddressBookBuilder.setPeople(1, builder); AddressBookBuilder.addPeople(builder); System.out.println("AddressBookBuilder.toString():-"+AddressBookBuilder.toString()); return builder; } //Data preparation End] } |
Create PersonModel class this is use to take the input from the UI browser.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package com.example.tutorial.protos; public class PersonModel { public int id; public String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "PersonModel [id=" + id + ", name=" + name + "]"; } } |
- GET CAll
Output
name: “siddhu”
id: 126
email: “shdhumale@gmail.com”
phones {
number: “1111111”
type: HOME
}
phones {
number: “222222222”
type: MOBILE
}
- POST CAll
request body :-
{
“id”:”1″,
“name”:”Dhumale”
}
Output:-
name: “Dhumale”
id: 1
email: “shdhumale@gmail.com”
phones {
number: “1111111”
type: HOME
}
phones {
number: “222222222”
type: MOBILE
}
- PUT CALL
http://localhost:8080/person/126
request body :-
{
“name”:”dhumale”
}
Output:-
name: “dhumale”
id: 126
email: “shdhumale@gmail.com”
phones {
number: “1111111”
type: HOME
}
phones {
number: “222222222”
type: MOBILE
}
- DELETE CALL
http://localhost:8080/person/126
Output:-
name: “siddhu”
email: “shdhumale@gmail.com”
phones {
number: “1111111”
type: HOME
}
phones {
number: “222222222”
type: MOBILE
}
As you can see from the above iamges all our rest is giving proper data from the proto generated object.
Now lets create the producer and have all the same method but they accept the parameter from url and reply on the same to consumer.
4- Create a producerspringboot application.
Add our Proto depencies in pom.xml of this project
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.19.0</version> </dependency> <plugin> <groupId>com.github.os72</groupId> <artifactId>protoc-jar-maven-plugin</artifactId> <version>3.11.4</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>run</goal> </goals> <configuration> <protocVersion>3.19.0</protocVersion> <inputDirectories> <include>src/main/protobuf</include> </inputDirectories> <outputDirectory>src/main/java</outputDirectory> </configuration> </execution> </executions> </plugin> |
Our pom.xml will be like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.0-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.siddhu</groupId> <artifactId>producerspringboot</artifactId> <version>0.0.1-SNAPSHOT</version> <name>producerspringboot</name> <description>This example shows the produce data using Proto file </description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.19.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>com.github.os72</groupId> <artifactId>protoc-jar-maven-plugin</artifactId> <version>3.11.4</version> <executions> <execution> <phase>generate-sources</phase> <goals> <goal>run</goal> </goals> <configuration> <protocVersion>3.19.0</protocVersion> <inputDirectories> <include>src/main/protobuf</include> </inputDirectories> <outputDirectory>src/main/java</outputDirectory> </configuration> </execution> </executions> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <releases> <enabled>false</enabled> </releases> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <releases> <enabled>false</enabled> </releases> </pluginRepository> </pluginRepositories> </project> |
Add all the Proto created file in src/java as shown below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | package com.siddhu; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import com.example.tutorial.protos.AddressBook; import com.example.tutorial.protos.Person; import com.example.tutorial.protos.Person.PhoneNumber; import com.example.tutorial.protos.Person.PhoneType; import com.example.tutorial.protos.PersonModel; @RestController public class ProducerWebController { @Autowired RestTemplate restTemplate; // GET Method - To Select the data. @RequestMapping(value = "/person", method = RequestMethod.GET) public String getPerson() { return getData().toString(); } // POST Method :- To insert the data. @RequestMapping(value = "/person", method = RequestMethod.POST) public String createPerson(@RequestBody PersonModel personModel) { // HttpHeaders headers = new HttpHeaders(); // MediaType mediaType = new MediaType("application", "x-protobuf"); // List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>(); // acceptableMediaTypes.add(mediaType); // headers.setAccept(acceptableMediaTypes); // HttpEntity<PersonModel> entity = new HttpEntity<PersonModel>(personModel,headers); HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); HttpEntity<PersonModel> entity = new HttpEntity<PersonModel>(personModel,headers); Person.Builder builder = getData(); builder.setId(entity.getBody().getId()); builder.setName(entity.getBody().getName()); return builder.toString(); } // PUT Method :- To update the data. @RequestMapping(value = "/person/{id}", method = RequestMethod.PUT) public String updatePerson(@PathVariable("id") String id, @RequestBody PersonModel personModel) { HttpHeaders headers = new HttpHeaders(); MediaType mediaType = new MediaType("application", "x-protobuf"); List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>(); acceptableMediaTypes.add(mediaType); headers.setAccept(acceptableMediaTypes); HttpEntity<PersonModel> entity = new HttpEntity<PersonModel>(personModel,headers); Person.Builder builder = getData(); builder.setName(entity.getBody().getName()); return builder.toString(); } // DELETE Method :- To delete the data. @RequestMapping(value = "/person/{id}", method = RequestMethod.DELETE) public String deletePerson(@PathVariable("id") String id) { HttpHeaders headers = new HttpHeaders(); MediaType mediaType = new MediaType("application", "x-protobuf"); List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>(); acceptableMediaTypes.add(mediaType); headers.setAccept(acceptableMediaTypes); Person.Builder builder = getData(); builder.clearId(); return builder.toString(); } //Data preparation Start[ private Person.Builder getData() { Person.Builder builder = Person.newBuilder(); builder.setName("siddhu"); builder.setId(126); builder.setEmail("shdhumale@gmail.com"); System.out.println("builder.toString():-"+builder.toString()); PhoneNumber.Builder PhoneNumberBuilder = PhoneNumber.newBuilder(); PhoneNumberBuilder.setNumber("1111111"); PhoneNumberBuilder.setType(PhoneType.HOME); //builder.setPhones(0, PhoneNumberBuilder); PhoneNumber.Builder PhoneNumberBuilder1 = PhoneNumber.newBuilder(); PhoneNumberBuilder1.setNumber("222222222"); PhoneNumberBuilder1.setType(PhoneType.MOBILE); //builder.setPhones(1, PhoneNumberBuilder1); builder.addPhones(PhoneNumberBuilder).addPhones(PhoneNumberBuilder1); System.out.println("builder after adding PhoneNumberBuilder1.toString():-"+builder.toString()); AddressBook.Builder AddressBookBuilder = AddressBook.newBuilder(); //AddressBookBuilder.setPeople(1, builder); AddressBookBuilder.addPeople(builder); System.out.println("AddressBookBuilder.toString():-"+AddressBookBuilder.toString()); return builder; } //Data preparation End] } |
- GET CAll
Output
name: “siddhu”
id: 126
email: “shdhumale@gmail.com”
phones {
number: “1111111”
type: HOME
}
phones {
number: “222222222”
type: MOBILE
}
- POST CAll
request body :-
{
“id”:”1″,
“name”:”Dhumale”
}
Output:-
name: “Dhumale”
id: 1
email: “shdhumale@gmail.com”
phones {
number: “1111111”
type: HOME
}
phones {
number: “222222222”
type: MOBILE
}
- PUT CALL
http://localhost:8080/person/126
request body :-
{
“name”:”dhumale”
}
Output:-
name: “dhumale”
id: 126
email: “shdhumale@gmail.com”
phones {
number: “1111111”
type: HOME
}
phones {
number: “222222222”
type: MOBILE
}
- DELETE CALL
http://localhost:8080/person/126
Output:-
name: “siddhu”
email: “shdhumale@gmail.com”
phones {
number: “1111111”
type: HOME
}
phones {
number: “222222222”
type: MOBILE
}
Note:-You can also create the java file for the given proto files by running project with “clean build” in maven. As we have protoc-jar-maven-plugin in our pom.xml and our protoc in class path it will create java files at the desired location. By creating java file by this we dont even need to remove this @java.lang.Override and it contains another line i.e. @SuppressWarnings({“unused”})
Source code
https://github.com/shdhumale/consumerspringboot.git
https://github.com/shdhumale/producerspringboot.git
No comments:
Post a Comment