The following, if there is a problem, please point out, thank you!
The last one said something, this is the SPRINGMVC HTTP serialization/deserialization, here is simply how to use this feature in Springboot.
People who have used native Netty http may be familiar with HTTP serialization, and the meaning in Springmvc is the same as in Netty. HTTP serialization (or HTTP message encoding) is the conversion of a Java class into a binary stream output to an HTTP Body;http deserialization, which translates an HTTP message into a Java class inside the program. With HTTP deserialization, there is no need to go to a request.getparam ("xxx") to get the parameters, with HTTP serialization, you do not have to directly through the response.getWriter.write to output results. For simplicity, HTTP serialization/deserialization unification is called HTTP serialization.
HTTP serialization is the function that a qualified controller framework should have, and with it, in many scenarios, the controller's approach simply writes the line of code that invokes the service, greatly simplifying the complexity of the business code logic.
In Springmvc, you can write the Java class directly as a parameter in the controller's code, which is done by pairing the parameter name with the property name, using Request.getparam ("XXX"). In the front and back end separation, sometimes need to deal with some very deep, very complex parameters, this time through the ordinary form-data is not a good choice, they are poor readability, difficult to parse. This scenario directly uses some text format (Json/xml) serialization/deserialization is a good choice, the coding is very simple, but also easy to unify the import processing. In Springmvc, it is simply to annotate the request parameters and return values through @requestbody and @responsebody, which is believed to have used Springmvc.
It's OK to not use JSON format to transfer data rows, of course, HTTP Although the name is called text, but the same can be used to transfer binary data, that is, all the format of data. This may seem strange, but in places where HTTP communication is done with non-web front ends, the data format for custom HTTP is common, such as HTTP-based RPC services. RPC in order to meet the universality, low consumption, the general choice of cross-language, time performance, compression ratio of the serialization format, such as Protobuf.
SPRINGMVC itself provides the HTTP serialization of the PROTOBUF, In the Spring-web package, there is a class called Org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter, which is used to deal with data in the PROTOBUF format, it is interesting to try.
Referring to Protobufhttpmessageconverter, we can write an HTTP serialization of our own, using the Java native serialization read-write object, the code is as follows.
Package Pr.study.springboot.configure.mvc.converter;import Java.io.ByteArrayInputStream;import Java.io.ByteArrayOutputStream;import java.io.IOException;import Java.io.ObjectInputStream;import Java.io.ObjectOutputStream;import Java.nio.charset.Charset;import java.util.Base64;import Org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.http.HttpInputMessage;import org.springframework.http.HttpOutputMessage;import Org.springframework.http.MediaType;import Org.springframework.http.converter.AbstractHttpMessageConverter;import org.springframework.http.converter.HttpMessageNotReadableException;import org.springframework.http.converter.HttpMessageNotWritableException;import org.springframework.util.StreamUtils;import Pr.study.springboot.bean.BaseBean; Public classJavaserializationconverterextendsabstracthttpmessageconverter<object> {PrivateLogger Logger = loggerfactory.GetLogger(Javaserializationconverter.class); Public Javaserializationconverter() {The type of consumes (req) and produces (RESP) are indicated in the constructor method, indicating that the type will use this converter Super(New mediatype("Application","X-java-serialization", Charset.forname("UTF-8"))); }@Override protected Boolean supports(Class<?> clazz) {returnBasebean.class.IsAssignableFrom(Clazz); }@Override protectedObjectreadinternal(CLASS<?extendsObject> Clazz, Httpinputmessage inputmessage)throwsIOException, Httpmessagenotreadableexception {byte[] bytes = Streamutils.Copytobytearray(InputMessage.GetBody());//Base64 enables visualization of binary data for easy testingBytearrayinputstream Bytesinput =NewBytearrayinputstream (Base64.Getdecoder().Decode(bytes)); ObjectInputStream ObjectInput =NewObjectInputStream (Bytesinput);Try{returnObjectInput.ReadObject(); }Catch(ClassNotFoundException e) {LOGGER.Error("Exception when Java deserialize, the input is:{}",NewString (Bytes,"UTF-8"), E);return NULL; } }@Override protected void writeinternal(Object T, Httpoutputmessage outputmessage)throwsIOException, httpmessagenotwritableexception {bytearrayoutputstream bytesoutput =NewBytearrayoutputstream (); ObjectOutputStream ObjectOutput =NewObjectOutputStream (Bytesoutput); ObjectOutput.writeobject(t);//Base64 enables visualization of binary data for easy testingOutputmessage.GetBody().Write(Base64.Getencoder().encode(Bytesoutput.Tobytearray())); }}
You can use the following code to configure this converter
@Override Public void extendmessageconverters(List//Add only a new converter, do not delete the default added //If you want to delete can use Converters.clear () //When only one converter is available, the delegate request and response defaults to the converter representative mediatype //recommend using this method to add converterConverters.Add(New Javaserializationconverter()); }///// Add converter The second way, will delete the original converter//@Bean//Public httpmessageconverter<object> Javaserializationconverter () {//return new Javaserializationconverter ();// }///// Add converter The Third way, will delete the original converter//@Override//public void Configuremessageconverters (list//Converters.add (New Javaserializationconverter ());// }
The above code is placed in the subclass of Webmvcconfigureradapter that we write, and if you use my code, it is in pr.study.springboot.configure.mvc.SpringMvcConfigure. The first approach is recommended, if your business determines that there is only one HTTP serialization method, you can use the following to improve some efficiency.
Note In Converter's code that it is important to specify the type of mediatype in the constructor (using the parent class's construction method is a good choice), indicating that the type has the opportunity to use the converter. The specific is:
- The mediatype specified by Headers.content-type in the HTTP request determines which converter to use (the Controller method supports consumes this mediatype) to handle the serialization of the Req body;
- The mediatype specified by the Headers.accept in the HTTP request determines which converter (Controller method to support produces this mediatype) is used to handle the serialization of the Req's corresponding RESP body, corresponding to the processing success RESP returns a content-type that belongs to the accept subset;
JSON serialization uses the following JSON
{"id":123,"name":"helloworld","email":"[email protected]","createTime":"2017-12-17 15:22:55"}
Java serialization uses the following data
rO0ABXNyAB1wci5zdHVkeS5zcHJpbmdib290LmJlYW4uVXNlcrt1879rvWjlAgAESgACaWRMAApjcmVhdGVUaW1ldAAQTGphdmEvdXRpbC9EYXRlO0wABWVtYWlsdAASTGphdmEvbGFuZy9TdHJpbmc7TAAEbmFtZXEAfgACeHIAIXByLnN0dWR5LnNwcmluZ2Jvb3QuYmVhbi5CYXNlQmVhbklx6Fsr8RKpAgAAeHAAAAAAAAAAe3NyAA5qYXZhLnV0aWwuRGF0ZWhqgQFLWXQZAwAAeHB3CAAAAWBjWqyYeHQAEGhlbGxvd29ybGRAZy5jb210AApoZWxsb3dvcmxk
The code used for testing is as follows:
@RestController@RequestMapping("/users") Public classUsercontroller {@Autowired PrivateUserService UserService;@GetMapping("/{id}") PublicUserGetuserbyid(@PathVariable LongID) {returnUserService.Getuserbyid(ID); }@PostMapping PublicUserCreateUser(@RequestBodyUser user) {System.Err.println("Create an User:"+ user);returnUser }}@Service Public classUserserviceimplImplementsUserService {@Override PublicUserGetuserbyid(LongID) {User user =New User(); User.setId(123L); User.SetName("HelloWorld"); User.Setemail("[email protected]"); User.Setcreatetime(NewDate ());returnUser }}
Below are some of the running result graphs, which can be used to see the effect of accept and content-type on serialization deserialization.
- GET + ACCEPT:APPLICATION/X-JAVA-SERIALIZATION,RESP using Java serialization to return
- GET + ACCEPT:APPLICATION/JSON,RESP uses JSON serialization to return
- POST + content-type:application/x-java-serialization + accept:application/x-java-serialization,req and resp all use Java serialization
- POST + content-type:application/x-java-serialization + accept:application/json,req using Java serialization, RESP using JSON serialization
- POST + Content-type:application/json + accept:application/json,req and resp all use JSON serialization
- POST + Content-type:application/json + accept:application/x-java-serialization,req using JSON serialization, RESP using Java serialization
To test this, post returns the user object, directly returning the base type (wrapper class/bigdecimal) and the string, not the normal object serialization, which is processed to return in a common format that uses them directly.
In fact, according to the application of REQ/RESP application scenario, to determine the controller method consumes and produces, ignoring these two properties usually there is no problem, SPRINGMVC the internal mediatype matching mechanism is better.
Let's talk about other little things.
SPRINGMVC uses the Jackson framework to process JSON by default. Jackson also needed some configuration in practical use, such as the serialization of properties that turned off null values, the serialization format of time, and so on. To configure Jackson, you only need to configure the injection objectmapper yourself. As follows:
Package Pr.study.springboot.configure.mvc.json;import Java.text.SimpleDateFormat;import Org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import com.fasterxml.jackson.annotation.JsonInclude.Include;import Com.fasterxml.jackson.databind.ObjectMapper;/*** Jackson's core is Objectmapper, where Objectmapper is configured to control certain features of Jackson that Springboot uses */@Configuration Public classMyobjectmpper {@Bean PublicObjectmapperGetobjectmapper() {Objectmapper mapper =New Objectmapper(); Mapper.setserializationinclusion(Include.Non_null);///non-serialized NULL propertyMapper.Setdateformat(NewSimpleDateFormat ("Yyyy-mm-dd HH:mm:ss"));//default time-serialization format returnMapper }}
What if you want to use Fastjson (some companies will require the same jar package for these base components to facilitate extended maintenance)? The same way as in the SPRINGMVC, you can configure a fastjsonhttpmessageconverter on the line. The configuration in Springboot is similar to the Java serialization we wrote above, and the following code is added to the MVC configuration class:
@Override Public void extendmessageconverters(List//Add only a new converter, do not delete the default added //If you want to delete can use Converters.clear () //When only one converter is available, the delegate request and response defaults to the converter representative mediatype //recommend using this method to add converterConverters.Add(New Javaserializationconverter());//Use Fastjson instead of JacksonFastjsonhttpmessageconverter Fastjsonconverter =New Fastjsonhttpmessageconverter(); Fastjsonconfig Fastjsonconfig =New Fastjsonconfig(); Fastjsonconfig.Setserializerfeatures(Serializerfeature.Writemapnullvalue);//serialization of NULL propertyFastjsonconfig.Setdateformat("Yyyy-mm-dd HH:mm:ss");//default time-serialization formatFastjsonconverter.Setfastjsonconfig(Fastjsonconfig); Converters.Add(Fastjsonconverter); System.Err.println(converters); }
In other words, the official document says a custom Jsonserializer, what's the use of this? Simply put, you can specify the JSON serialization format of any object yourself, such as time you can serialize into Chinese format, RGB color is generally three byte storage, you can serialize into CSS common format.
I didn't use this function, but I found an example on the Internet, so you can refer to how to serialize the RGB color into CSS format in JSON.
Code Related:
Https://gitee.com/page12/study-springboot/tree/springboot-3
Https://github.com/page12/study-springboot/tree/springboot-3
Springboot Learning (iii)--HTTP serialization/deserialization Httpmessageconverter