文章目录
定义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;