SSM (14) annotation-based HTTP anti-reset plugin

Source: Internet
Author: User
Tags getmessage

SSM (14) annotation-based HTTP anti-reset plugin

Objective

For what we often use today, RESTful API we usually need to uniquely identify the request, that is, each time with a request number, such as reqNO .

For the request of this kind of operation database in warehousing we generally want to guarantee his uniqueness, a request number is usually only used once, so we need to add a verification mechanism to this request.

The idea for this requirement is to customize annotation and annotate only the interfaces that need to be verified. Then, by using the interface of the annotation, each request number is stored in Redis , and each time it is judged whether there is a request number.

Take a look at the actual effect of adding this plugin:



Custom annotations

First we want to customize an annotation:

1234567 @Target (Elementtype.method) @Retention (retentionpolicy.runtime) @Documented public @interface checkreqno { String desc() default "";}

(PS: This is not too much to explain the relevant knowledge of annotations).

First use @interface to declare an annotation. We then use Java the three meta annotations we provide to define CheckReqNo annotations.

It @Target shows where this annotation is used, the use ElementType.METHOD indicates that it is applied to the method, and there are other values to see java.lang.annotation.ElementType the enumeration type.

@RetentionThe annotations indicate the extent to which our annotations are valid, and the configuration here RetentionPolicy.RUNTIME indicates that they can be obtained by reflection at run time.

@DocumentedThe literal meaning should also be guessed to be used to generate JavaDoc the document.

The method that defines one is desc() not actually used, but if you need to customize some of the requirements when using annotations, you can write them in filed(域) this way, and you can get specific values by reflection.
such as: @CheckReqNo(desc = "abc") the value that can be obtained "abc" .

Facet annotations

The previous idea was to slice through all the methods that used the annotation:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 @Aspect@Componentpublic class Reqnodrcaspect { private static Logger Logger = Loggerfactory.getlogger (reqnodrcaspect.class); @Value ("${redis.prefixreq:reqno}") private String prefixreq;@Value ("${redis.day:1}") private long day; @Autowiredprivate redistemplate<string, string> redistemplate;@PostConstructpublic void init() throws Exception { Logger.info ("Ssm-request-check init ...");}@Pointcut ("@annotation (com.crossoverJie.request.anotation.CheckReqNo)") public void checkrepeat() { }@Before ("checkrepeat ()") public void before(Joinpoint joinpoint) throws Exception { Baserequest request;request = getbaserequest (joinpoint);if (Request! = null) { final String reqno = Request.getreqno ();if (Stringutil.isempty (reqno)) {throw New RuntimeException ("reqno cannot be Empty"); }else{try {String tempreqno = Redistemplate.opsforvalue (). Get (Prefixreq +reqno); Logger.debug ("tempreqno=" +tempreqno);if ((Stringutil.isempty (tempreqno))) {Redistemplate.opsforvalue (). Set (Prefixreq + reqno, Reqno, Day, timeunit.days);}else{throw New RuntimeException ("Duplicate request number, reqno=" +reqno); } }catch (Redisconnectionfailureexception e) {Logger.error ("Redis operation exception", e);throw New RuntimeException ("Need Redisservice"); }}} }public static baserequest getbaserequest(joinpoint joinpoint) throws Exception { Baserequest returnrequest =null;object[] arguments = Joinpoint.getargs ();if (arguments! = null && arguments.length > 0) { Returnrequest = (baserequest) arguments[0];}return returnrequest;}}

Use @Aspect to define a slice.
Where prefixReq,day the domain can customize the prefix of the cache request number key and the time of the cache.

The key point is to use
@Pointcut("@annotation(com.crossoverJie.request.anotation.CheckReqNo)")
A pointcut is defined so that all @CheckReqNo annotations used are intercepted.

The next logic is simpler, and is intercepted before each request.

Go first to Redis see if this request number ( ps:反射获取 ) exists, and if it does not exist, then pass and cache the request number for this time. Throws an exception if it exists.

Using annotations

You can jdbc.properties customize the prefix and cache time in the configuration file

1234 #redis前缀redis. Prefixreq=reqno#redis Cache Time Default unit is day Redis.day=1

Not defined or Yes, default values are used.

Since this annotation needs to be added to the controller layer, we have to use the CGLIB proxy.
Here is a pit where you need to CGLIB configure the open configuration to our web.xml

1234567891011 <!--Spring MVC servlet --- <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.dispatcherservlet</servlet-class> <init-param> <param-name>contextconfiglocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> <async-supported>true</async-supported> </servlet>

In the file defined here spring-mvc.xml , the springMVC child container that is otherwise located cannot be loaded by the parent container.

Usage examples:

1234567891011121314151617181920212223 @CheckReqNo@RequestMapping (value = "/createrediscontent", method = Requestmethod.post) @ResponseBodyPublic baseresponse<nullbody> createrediscontent(@RequestBody rediscontentreq rediscontentreq) { baseresponse<nullbody> response =new Baseresponse<nullbody> ();Rediscontent rediscontent =new Rediscontent (); try {Commonutil.setlogvaluemodeltomodel (rediscontentreq,rediscontent); Rediscontentmapper.insertselective (rediscontent); Response.setreqno (Rediscontentreq.getreqno ()); Response.setcode (StatusEnum.SUCCESS.getCode ()); Response.setmessage (StatusEnum.SUCCESS.getMessage ()); }catch (Exception e) {Logger.error ("System error", E);Response.setreqno (Response.getreqno ()); Response.setcode (StatusEnum.FAIL.getCode ()); Response.setmessage (StatusEnum.FAIL.getMessage ()); }return response;}
Unified Exception Controller
1234567891011121314151617181920212223242526272829 /*** * Classname:errorcontroller <br/> * Function: Error exception unified processing. <br/> *@author Crossoverjie*@version*@since JDK 1.7*/@ControllerAdvicepublic class Errorcontroller { private Logger Logger = Loggerfactory.getlogger (this.getclass ()); @ExceptionHandler (Exception.class) @ResponseStatus (Httpstatus.ok) @ResponseBody Public Object processunauthenticatedexception(nativewebrequest request, Exception e) { Logger.error ("Request exception:", e);baseresponse<nullbody> response =new Baseresponse<nullbody> ();Response.setcode (StatusEnum.FAIL.getCode ());if (e instanceof runtimeexception) { Response.setmessage (E.getmessage ()); }else {Response.setmessage (StatusEnum.FAIL.getMessage ()); }return response;}}

This way, when the controller layer is abnormal, it will enter here for a unified return.

Summarize

At this point the entire plug-in process has been all OK, from which you can see the Spring AOP various benefits in the actual development.
Previous articles have also been applied to:

    • Using Redis in Javaweb applications
    • Dynamically Switching data sources

Unknowingly this small white Primer SSM series has been updated 14, in GitHub also has more than 500 stars, during and many friends have had exchanges, discussion, thank you for your support.

Next may not be very likely to update the series, because the blogger now in the project group is currently more popular SpringBoot+SpringCloud and Docker the way to carry out the structure, so the center of gravity will certainly be moved to this aspect, after the use of the SpringBoot trust that you will certainly not go back.

So after that I will continue to update SpringBoot+SpringCloud the relevant articles, welcome continuous attention, continuous shooting bricks ( ps:这个插件也会用springBoot重写一遍 )

SSM (14) annotation-based HTTP anti-reset plugin

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.