Some tips for using SPRING-MVC

Source: Internet
Author: User
Tags aliases app service decrypt object object serialization throw exception

Token Verification on APP service side

The interceptor uses the @Authorization annotation method to intercept the request, and the token information is removed from the HTTP header to verify that it is legitimate. Illegal direct return 401 error, the legal token corresponding to the user key in the request to continue execution. Specific implementation code:

1234567891011121314151617181920212223242526272829303132 public boolean prehandle (httpservletrequest request,httpservletresponse response, Object handler) throws Exception {///AS The result is not mapped to the method directly through if (! ( Handler instanceof Handlermethod) {return true;} Handlermethod Handlermethod = (handlermethod) handler; method = Handlermethod.getmethod ();//Get tokenstring token = Request.getheader (httpheadername) from the header; if (toke n! = null && token.startswith (httpheaderprefix) && token.length () > 0) {token = token.substring (http Headerprefix.length ());//verify Tokenstring key = Manager.getkey (token), if (key = null) {//If token verification succeeds, the user ID corresponding to token There is a request to facilitate the subsequent injection of Request.setattribute (Request_current_key, KEY); return true;}} If the validation token fails and the method notes Authorization, a 401 error is returned if (method.getannotation (authorization.class) = null) {Response.setstat US (httpservletresponse.sc_unauthorized); Response.setcharacterencoding ("GBK"); Response.getwriter (). Write ( Unauthorizederrormessage); Response.getwriter (). Close (); return false;} In order to prevent the use of someWrite KEY directly in Request_current_key, set it to Nullrequest.setattribute (Request_current_key, null); return true;}

After the interceptor, the modified @CurrentUser parameters are injected using the parser. Remove the user key from the request before it is saved, and get the corresponding user object and inject it into the parameter. Specific implementation code:

123456789101112131415161718192021222324252627282930313233 @Overridepublic boolean supportsparameter (methodparameter parameter) {Class clazz;try {clazz = Class.forName ( Usermodelclass);} catch (ClassNotFoundException e) {return false;} If the parameter type is User and a CurrentUser annotation is supported, if (Parameter.getparametertype (). IsAssignableFrom (Clazz) && Parameter.hasparameterannotation (Currentuser.class)) {return true;} return false;}   @Overridepublic Object resolveargument (methodparameter parameter, Modelandviewcontainer Mavcontainer, Nativewebrequest webRequest, Webdatabinderfactory binderfactory) throws Exception {//Remove authentication to the logged-in user Idobject object = Webr Equest.getattribute (Authorizationinterceptor.request_current_key, requestattributes.scope_request); if (Object! = NULL) {String key = String.valueof (object);//Query from database and return object Usermodel = Usermodelrepository.getcurrentuser (key); if ( Usermodel! = null) {return usermodel;} There is a key but not the user, throw exception throw new Missingservletrequestpartexception (Authorizationinterceptor.request_current_key);} Return the NU directly without keyLlreturn null;}

Detailed analysis: RESTful login Design (Token authentication based on Spring and Redis)

See Source: Scienjus/spring-restful-authorization

Packaged Tool class: Scienjus/spring-authorization-manager

Using aliases to accept parameters for an object

It is common for the parameter names in the request to be different from the parameter names defined in the code, and in this case Spring provides several native methods:

For @RequestParam example, you can directly specify the value as an alias (and @RequestHeader the same), such as:

123 Public String Home (@RequestParam ("user_id") long userId) {return "Hello" + userId;}

For @RequestBody , because it makes use of Jackson to convert Json to an object, you can use @JsonProperty the value to specify an alias, for example:

12345678 Public String Home (@RequestBody user user) {return "Hello" + User.getuserid ();} Class User {@JsonProperty ("user_id") Private long UserId;}

However, when you use an object's properties to accept parameters, you cannot specify the alias directly from the method above, for example:

123 Public String Home (user user) {return "Hello" + User.getuserid ();}

This is the time to use DataBinder to manually bind properties and aliases, and the article I found on the Stack Overflow is a good way to do this, not to repeat the wheel.

Turn off default by request suffix name to Judge Content-type

The development habit of the previously inherited project is to use the. html as the suffix of the request, which is not a problem on Struts2 (because it Struts2 a few ways to handle Json). But when I take over the change to Spring MVC, I'm @ResponseBody not going to find a converter error when I use the returned object.

This is because Spring MVC defaults to the content-type of the request with the suffix named. html text/html , and the @ResponseBody returned Content-type is application/json that there is no one converter that supports such conversions. So it is necessary to manually turn off the setting of Content-type by suffix and set the default Content-type to application/json :

123456789 @Configurationpublic class Webmvcconfig extends Webmvcconfigureradapter {@Overridepublic void Configurecontentnegotiation (Contentnegotiationconfigurer configurer) {configurer.favorpathextension (false). Defaultcontenttype (Mediatype.application_json);}}
Change the default Json serialization scheme

Projects sometimes have their own unique Json serialization scheme, such as the more common use 0 / 1 substitution false / true , or by "" substitution null , as the @ResponseBody default is to use MappingJackson2HttpMessageConverter , only to implement ObjectMapper their own Pass in this converter:

1234567891011121314151617181920 public class Customobjectmapper extends Objectmapper {public customobjectmapper () {super (); This.getserializerprovider (). Setnullvalueserializer (New jsonserializer<object> () {@Overridepublic void serialize (Object value, Jsongenerator Jgen, Serializerprovider provider) throws IOException {jgen.writestring ("");}}); Simplemodule module = new Simplemodule (); Module.addserializer (Boolean.class, New jsonserializer<boolean> () {@ overridepublic void Serialize (Boolean value, Jsongenerator Jgen, Serializerprovider provider) throws IOException {JGEN.W Ritenumber (value 1:0);}); This.registermodule (module);}}
Json in an automatic encryption/decryption request

Type conversion issues

Related to @RequestBody and @ResponseBody are generally in the mappingjackson2httpmessageconverter resolved, want to automatically encrypt/decrypt only need to inherit this class and override readinternal / writeinternal method:

12345678910111213141516171819 @Overrideprotected Object readinternal (class<?> clazz, Httpinputmessage inputmessage) throws IOException, httpmessagenotreadableexception {//decrypt string json = Aesutil.decrypt (Inputmessage.getbody ()); Javatype Javatype = Getjavatype (clazz, NULL);//Convert return This.objectMapper.readValue (JSON, javatype);} @Overrideprotected void Writeinternal (Object object, Httpoutputmessage outputmessage) throws IOException, httpmessagenotwritableexception {//using Jackson's objectmapper to convert Java objects to Json stringobjectmapper mapper = new Objectmapp ER (); String json = Mapper.writevalueasstring (object);//Encrypt string result = Aesutil.encrypt (JSON);//Output Outputmessage.getbody ( ). Write (Result.getbytes ());}
Annotation-based sensitive word filtering function

The project needs to filter the content posted by the user and replace the sensitive words with the * special characters. Most WEB projects handle this requirement by selecting a filter ( Filter ), wrapping a layer in the filter, Request Wrapper and overriding methods such as getParameter :

123456789101112131415161718192021222324252627282930313233343536373839 public class Safetextrequestwrapper extends Httpservletrequestwrapper {public Safetextrequestwrapper ( HttpServletRequest req) {super (req);}   @Overridepublic map<string, String []> getparametermap () {map<string, string []> parammap = Super.getp Arametermap (); for (String [] values:paramMap.values ()) {for (int i = 0; i < values.length; i++) {values [i] = Sensi Tiveutil.filter (values [i]);}} return parammap;}   @Overridepublic string GetParameter (string name) {return Sensitiveutil.filter (Super.getparameter (name));}}  public class Safetextfilter implements Filter {@Overridepublic void init (Filterconfig filterconfig) throws Servlet Exception { }  @Overridepublic void DoFilter (ServletRequest request, servletresponse response, Filterchain Chain) throws IOException, servletexception {safetextrequestwrapper safetextrequestwrapper = new Safetextrequestwrapper ((httpservletrequest) request); Chain.dofilter (safetextrequestwrapper, response);}   @OverriDepublic void Destroy () { }}

However, there are some obvious problems, such as the inability to control what information is filtered. If the user registers the mailbox or the password also carries the kind fuck of sensitive words, that is the accidental injury.

So instead of using spring MVC's Formatter to expand, just @RequestParam use annotations on the parameters @SensitiveFormat , and Spring MVC automatically filters the sensitive words as it injects the attribute. Both convenient and not accidental, the implementation method is as follows:

Statement @SensitiveFormat Annotations:

12345 @Target ({Elementtype.field, elementtype.parameter}) @Retention (retentionpolicy.runtime) @Documentedpublic @ Interface Sensitiveformat {}

Create the SensitiveFormatter class. Implement an Formatter interface that overrides the method parse that transforms the received content into an object, filtering the received content in the method:

1234567891011 public class Sensitiveformatter implements formatter<string> {@Overridepublic string parse (string text, Locale Loc Ale) throws ParseException {return sensitiveutil.filter (text);} @Overridepublic string Print (String object, Locale Local E) {return object;}}

Create the SensitiveFormatAnnotationFormatterFactory class, implement the AnnotationFormatterFactory interface, @SensitiveFormat and bind it SensitiveFormatter :

12345678910111213141516171819 public class Sensitiveformatannotationformatterfactory implements Annotationformatterfactory<sensitiveformat > {@Overridepublic set<class<?>> getfieldtypes () {set<class<?>> fieldtypes = new HashSet <> (); Fieldtypes.add (String.class); return fieldtypes;} @Overridepublic printer<?> getprinter (sensitiveformat annotation, class<?> fieldtype) {return new Sensitiveformatter ();} @Overridepublic parser<?> getparser (sensitiveformat annotation, class<?> fieldtype) {return new Sensitiveformatter ();}}

The final SensitiveFormatAnnotationFormatterFactory registration will be in Spring MVC:

123456789 @Configurationpublic class Webmvcconfig extends Webmvcconfigureradapter {@Overridepublic void Addformatters ( Formatterregistry registry) {Registry.addformatterforfieldannotation (new Sensitiveformatannotationformatterfactory ()); Super.addformatters (registry);}}
Log the returned content of the request

Here is a more general approach, based on the filter implementation, so projects in non-Spring MVC can also be used.

First Import commons-io :

12345 <dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId>< Version>2.4</version></dependency>

Need to use this library TeeOutputStream , this class can be a content output to two branches of the output stream, which is encapsulated as ServletOutputStream :

1234567891011121314151617181920212223242526272829303132333435 public class Teeservletoutputstream extends Servletoutputstream {private final teeoutputstream teeoutputstream; Eeservletoutputstream (OutputStream one, outputstream) {this.teeoutputstream = new Teeoutputstream (one, both);} @Over Ridepublic Boolean IsReady () {return false;} @Overridepublic void Setwritelistener (Writelistener listener) {} @Override public void Write (int b) throws IOException {this.teeOutputStream.write (b);} @Overridepublic void Flush () throws Ioexce ption {Super.flush (); This.teeOutputStream.flush (); @Overridepublic void Close () throws IOException {super.close (); th Is.teeOutputStream.close ();}}

Then create a filter that overrides the original response getOutputStream method:

123456789101112131415161718192021222324252627282930313233 public class Loggingfilter implements Filter { private static final Logger Logger = Loggerfactory.getlogger (LOGGINGF Ilter.class);  @Overridepublic void init (Filterconfig filterconfig) throws Servletexception { } public void DoFilter (ServletRequest request, Final servletresponse response, Filterchain chain) throws IOException, Servletexce ption {final Bytearrayoutputstream bytearrayoutputstream = new Bytearrayoutputstream ();  Httpservletresponsewrapper responsewrapper = new Httpservletresponsewrapper ((httpservletresponse) response) {  Private Teeservletoutputstream teeservletoutputstream;  @Overridepublic servletoutputstream getoutputstream () Throws IOException {return new Teeservletoutputstream (Super.getoutputstream (), Bytearrayoutputstream);}}; Chain.dofilter (Request, responsewrapper); String Responselog = bytearrayoutputstream.tostring (); if (logger.isinfoenabled () &&! Stringutil.isempty (Responselog)) {logger.info (Responselog);}}  @Overridepublic void Destroy () { }}

super.getOutputStream ()and ByteArrayOutputStream respectively as two sub-branches, the former will return the content to the client, the latter use the toString method to obtain the output content.

Other thought to add ...

The original is transferred from
Scienjus ' s Blog

Some tips for using SPRING-MVC (turn)

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.