SPRINGMVC Custom Configuration Message converter trample Pit summary

Source: Internet
Author: User
Tags getmessage

Problem description

Recently encountered a problem in the development time, SPRINGMVC page to the background of the data, usually I do so, in the foreground to the data into a JSON, in the background interface using @requestbody to define an object to receive, but this data can not pass, reported 400 error, The reason is also very easy to think of, the object has a property is an object, the Property object is defined by the abstract class, he has a few concrete implementations, the specific implementation of the fields are not the same, SPRINGMVC is not automatically identify and inject you use which implementation class. So I can't pass it over.

The passed object is as follows:

@Data  Public class activityrule {    ... Private Ruledetail Ruledetail; // Note that the ruledetail here is an abstract class    ... }
Solution:

Using a custom message converter, first let's look at spring's message converters

SPRINGMVC Message Converter (httpmessageconverter)

We have used both @requestbody and @responsebody annotations, their role is to pass the data in the foreground to the background, the data in the request message through the SPRINGMVC processing into a self-defined object, In this process first SPRINGMVC will go to the request header to find a contenttype attribute, and then go to the match to handle this type of message converter, and return the data, and then convert the object into a response message.

Describe the ContentType property:

ContentType is a property in Requestheader, which is used to describe the format of a string in the body, such as text,json,xml,html. Springmvc parse the request, the first through this head, in order to determine what format to use to parse the request body of the string, for the response message, the browser also through this property to determine how to handle the response packet return data. Introduction to the @requestbody/@ResponseBody annotations When you label an object with this annotation, the data mapping occurs during the request. Spring reads the data according to the Content-type type of the header part of the request object, matching the appropriate httpmessageconverter, and in response, Spring will traverse to find the httpmessageconverter that can be processed, based on the Accept attribute (comma-delimited) of the header portion of the Request object, by the type in the Accept.

Here we have a way of thinking, can we take over the request message to the object mapping process, as long as we get the JSON field, according to the content we know the need to map which class, at this point, we have the idea can be implemented, We can implement our ideas through spring's message converters,

By default, Spring uses Httpmessageconverter to take care ofWillPleaseRequest InformationConverted toOneRightLikeClassTypeForT), andWillRightLike type t) output

Abstracthttpmessageconverter<t>, let's look at a message converter I've defined for the Activityrule object above.

/*** Custom Message Converter Activityrule *@authorYogo.wang * @date 2017/10/25-5:43 pm.*/ Public classRulemessageconverterextendsAbstracthttpmessageconverter<activityrule> {     PublicRulemessageconverter () {Super(NewMediaType ("Application", "X-rule", Charset.forname ("UTF-8"))); } @Overrideprotected BooleanSupports (class<?>clazz) {        returnActivityrule.class. IsAssignableFrom (Clazz); } @OverrideprotectedActivityrule readinternal (class<?extendsActivityrule> Clazz, Httpinputmessage inputmessage)throwsIOException, httpmessagenotreadableexception {String temp= Streamutils.copytostring (Inputmessage.getbody (), Charset.forname ("UTF-8")); Map<String,Object> map = (map<string,object>) Json.parse (temp); RuleType RuleType= Ruletype.valueof (String) map.get ("RuleType")); String Ruledetail= Stringutils.substringafter (temp, "ruledetail\": "); Ruledetail=ruledetail.substring (0,ruledetail.length ()-1); Activityrule Rule=NewActivityrule (); Rule.setname (String) map.get ("Name"));        Rule.setruletype (RuleType); Switch(ruletype) { CaseLOGIN:rule.setRuleDetail (Json.parseobject (Ruledetail, Loginruledetail.class));  Break;  CaseROLE_UPGRADE:rule.setRuleDetail (Json.parseobject (Ruledetail, Upgraderuledetail.class));  Break;  CasePAY_AMOUNT:rule.setRuleDetail (Json.parseobject (Ruledetail, Rechargeruledetail.class));  Break; default: Rule.setruledetail (NULL); }        returnrule; } @Overrideprotected voidWriteinternal (Activityrule activityrule, Httpoutputmessage outputmessage)throwsIOException, Httpmessagenotwritableexception {}}

In the class above, when inheriting the abstract class Abstracthttpmessageconverter, we specified the generic as the class of the @requestbody callout, namely the Activityrule class, and then in the constructor in that class, we created a new media type " X-rule ", the name can be customized, and the appropriate encoding is specified, generally utf-8. In the overridden support () method, we determine whether the supported class is the same as the Activityrule class, only the same, the following method Readinternal, in this method, we need to get the JSON string from the request, Then manually map the JSON to an object yourself.

After writing this class is not finished, there are two steps to be required, first, in the spring configuration file will be configured on the message converter, as follows:

 <Mvc:annotation-driven>        <mvc:message-converters>            <Beanclass= "Com.ximalaya.cms.games.operation.activity.service.converter.RuleMessageConverter">                < Propertyname= "Supportedmediatypes">                    <List>                        <value>Application/json</value>                        <value>Application/x-rule</value>                    </List>                </ Property>            </Bean>            <Beanclass= "Org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>        </mvc:message-converters>    </Mvc:annotation-driven>

  second, in the Controller interface, you need to manually specify which interface can receive our custom media types. The following:

 /*** Save Rule Object *@paramRule *@return     */@RequestMapping (Method= Requestmethod.post,produces = {"Application/x-rule" }) @ResponseBody Publicresponsemessage Save (@requestbody  activityrule rule) {Log.info ("Begin to save activityrule:{}", rule); Try{ruleservice.saveavtivityrule (rule); returnResponsemessage.ok (); }Catch(Exception e) {returnResponsemessage.fail (E.getmessage ()); }    }

After the completion of the operation, in my test, stepped on two pits, need special instructions. When I run, the data is still too late, reported 415 error, said unsupported media type, later found in the front end of the AJAX call, found contenttype unchanged, changed as follows:

$.ajax ({method: $form. attr (' Method '), Traditional:true, url: $form. attr (' Action '), data:JSON.stringify (rule), ContentType:"Application/x-rule", DataType:"JSON", Success:function(ret) {//,......}, Error:function(message) {alert (' ERROR: ' +json.stringify (message)); }                    });

Run again, no problem, JSON field as expected to map to the object we want, but in front of the back, there are still errors, reported 406, according to the online solution, said is the lack of fastjson related packages, so the introduction of the relevant jar, or did not solve, card the most of the day, the end, Modified the contents of @requestmapping (), the magic solved the problem, as follows:

 /** * Save Rule Object * @param rule * @return*/@RequestMapping (Method= Requestmethod.post,produces = {" application/x-rule", "Application/json "}) @ResponseBody public responsemessage Save (@RequestBody activityrule rule) {Log.info ("Begin to save activityrule:{}", rule); Try{ruleservice.saveavtivityrule (rule); returnResponsemessage.ok (); }Catch(Exception e) {returnResponsemessage.fail (E.getmessage ()); }    }

I guess the reason may be, because the @responsebody is set, to convert the object to JSON format, but look at my code, @ResponseBody labeled class is Responsemessage, not activityrule!!!!, And Coontenttype was set up by me as a application/x-rule, so when I returned, I still walked my custom message converter, and two classes must be different, support returned false, and I added application/ After JSON, the Responsemessage object does not go through my custom message converter, but instead enters the spring default message converter with JSON contenttype and successfully maps to the response body.

SPRINGMVC Custom Configuration Message converter trample Pit summary

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.