定义LimitIp
package com.blove.ityustudy.annotation; import java.lang.annotation.*; @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface LimitIp { String ip() default ""; }
定义IpAspect
package com.blove.ityustudy.aop; import com.blove.ityustudy.annotation.LimitIp; import com.blove.util.IPUtils; import com.blove.util.RUtil; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; @Aspect @Component @Slf4j public class IpAspect { @Pointcut("@annotation(com.blove.ityustudy.annotation.LimitIp)") public void annotationPointcut() { } @Before("annotationPointcut()") public void beforePointcut(JoinPoint joinPoint) { log.info("beforePointcut"); } @After("annotationPointcut()") public void afterPointcut(JoinPoint joinPoint) { log.info("afterPointcut"); } /** * 拦截器具体实现 * @param pjp * @return JsonResult(被拦截方法的执行结果,或需要登录的错误提示。) */ @Around("annotationPointcut()") //指定拦截器规则;也可以直接把“execution(* com.xjj.........)”写进这里 public Object Interceptor(ProceedingJoinPoint pjp) { MethodSignature signature = (MethodSignature) pjp.getSignature(); Method method = signature.getMethod(); //获取被拦截的方法 String methodName = method.getName(); //获取被拦截的方法名 ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = servletRequestAttributes.getRequest(); LimitIp annotation = method.getAnnotation(LimitIp.class); String value = annotation.ip(); String ip = IPUtils.getRealIP(request); if(value.equals(ip)){ try { return pjp.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); return RUtil.error(throwable.getMessage()); } }else{ return RUtil.error("调用失败"); } } }
使用
@ApiOperation(value = "获取用户信息") @ApiImplicitParams({ // 参数说明 @ApiImplicitParam(name = "name", paramType = "query", value = "用户名字", dataType = "string", required = true), @ApiImplicitParam(name = "sex", paramType = "query", value = "性别", dataType = "Integer"), @ApiImplicitParam(name = "city", paramType = "query", value = "城市", dataType = "string"), }) @PostMapping(value = "/getUser") @LimitIp(ip = "127.0.0.1") public R<UserModel> getUser(@RequestParam(value = "name") String name, @RequestParam(value = "sex", required = false) Integer sex, @RequestParam(value = "city", required = false) String city) { if (!StringUtils.isBlank(city)) { return RUtil.ok(new UserModel().setName(name).setAge(sex).setCity(city)); } throw new CommonException("城市不能为空"); }
学习
1. @Target 这个注解可以放到那个位置,例如类上,方法上,属性上等
public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Formal parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE, /** * Type parameter declaration * * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE, /** * Module declaration. * * @since 9 */ MODULE }
2. @Retention
public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. */ SOURCE, /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. */ CLASS, /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * * @see java.lang.reflect.AnnotatedElement */ RUNTIME }
3. @Documented
AOP
满足 pointcut 规则的 joinpoint 会被添加相应的 advice 操作.
方法的生命周期:1,调用前,调用中,调用后(不关注结果),调用成功(调用返回异常),
Before-> After-> Around-> AfterReturning(AfterThrowing)
知道了生命周期就可以在任何地方切入了。
IOC
早期: 你需要啥,new一个就行了
ioc: 你需要啥,你先通过注解的方式告诉容器,让容器给你创建出来,当你需要的地方直接导入就行了
标注需求(@Component)
//读取classpath配置信息 @Data @Component @PropertySource(value = {"classpath:config.yml"},encoding = "utf-8") public class FileConfig { @Value("${staticAccessPath}") private String staticAccessPath; @Value("${uploadFolder}") private String uploadFolder; @Value("${min}") private int min; @Value("${max}") private int max; @Override public String toString() { return "FileConfig{" + "staticAccessPath='" + staticAccessPath + '\'' + ", uploadFolder='" + uploadFolder + '\'' + ", min='" + min + '\'' + ", max='" + max + '\'' + '}'; } }
导入需求( @Autowired)
@Autowired FileConfig fileConfig;