1.参数注解
/**
* 字段参数注解
*
* @author A.keung
* 2019/8/30 0030
* @Constraint 通过使用validatedBy指定与注解关联的验证器
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ParamsCheckConstraintValidator.class)
public @interface ParamsCheck {
//参数
String[] paramValues();
//提示
String message() default "params error";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
/**
* 字段参数注解验证器
*
* @author A.keung
* 2019/8/30 0030
*/
public class ParamsCheckConstraintValidator implements ConstraintValidator<ParamsCheck, Object> {
//注解参数
private List<String> paramValues;
@Override
public void initialize(ParamsCheck paramsCheck) {
//初始化时获取注解上的值
paramValues = Arrays.asList(paramsCheck.paramValues());
}
@Override
public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
return paramValues.contains(o);
}
}
@RequestMapping(value = "testParamsCheck",method = RequestMethod.POST)
public String testParamsCheck(@Validated @RequestBody User user) {
log.info(JSON.toJSONString(user));
return "OK";
}
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@TableName("t_user")
@NoArgsConstructor
//@AllArgsConstructor
public class User extends BaseEntity{
/**
* 密码
*/
@TableField("password")
private String password;
/**
* 手机
*/
@TableField("phone_number")
private String phoneNumber;
/**
* 邮箱
*/
@TableField("email")
private String email;
/**
* 昵称
*/
@TableField("nickname")
private String nickname;
/**
* 权限
*/
@ParamsCheck(paramValues = {"ADMIN","USER"})
@TableField("role")
private String role;
/**
* qqOpenId
*/
@TableField("qq_open_id")
private String qqOpenId;
/**
* 头像地址
*/
@TableField("figure_url")
private String figureUrl;
/**
* 是否启用
*/
@TableField("enable")
private Boolean enable;
private User(Builder builder) {
setId(builder.id);
setCreatedDatetime(builder.createdDatetime);
setModifiedDatetime(builder.modifiedDatetime);
setPassword(builder.password);
setPhoneNumber(builder.phoneNumber);
setEmail(builder.email);
setNickname(builder.nickname);
setRole(builder.role);
setQqOpenId(builder.qqOpenId);
setFigureUrl(builder.figureUrl);
setEnable(builder.enable);
}
public static final class Builder {
private Long id;
private Date createdDatetime;
private Date modifiedDatetime;
private String password;
private String phoneNumber;
private String email;
private String nickname;
private String role;
private String qqOpenId;
private String figureUrl;
private Boolean enable;
public Builder() {
}
public Builder id(Long val) {
id = val;
return this;
}
public Builder createdDatetime(Date val) {
createdDatetime = val;
return this;
}
public Builder modifiedDatetime(Date val) {
modifiedDatetime = val;
return this;
}
public Builder password(String val) {
password = val;
return this;
}
public Builder phoneNumber(String val) {
phoneNumber = val;
return this;
}
public Builder email(String val) {
email = val;
return this;
}
public Builder nickname(String val) {
nickname = val;
return this;
}
public Builder role(String val) {
role = val;
return this;
}
public Builder qqOpenId(String val) {
qqOpenId = val;
return this;
}
public Builder figureUrl(String val) {
figureUrl = val;
return this;
}
public Builder enable(Boolean val) {
enable = val;
return this;
}
public User build() {
return new User(this);
}
}
}
2.缓存注解
/**
* 部门缓存注解
*
* @author A.keung
* 2019/8/30 0030
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DeptCache {
//#user.name或jack
String keyExpr();
}
/**
* 部门缓存切面
*
* @author A.keung
* 2019/8/30 0030
*/
@Component
@Aspect
@Slf4j
public class DeptCacheAspect {
/**
* 对含有注解的方法进行处理
*
* @param joinPoint
* @return 返回值
*/
@Around("@annotation(com.ak.common.DeptCache)")
public Object process(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
Object result = null;
// 获取切入的方法对象
// 代理对象的,没有包含注解
Method m = ((MethodSignature) joinPoint.getSignature()).getMethod();
// 目标对象反射获取的method对象才包含注解
Method methodWithAnnotations = joinPoint.getTarget().getClass().getDeclaredMethod(joinPoint.getSignature().getName(), m.getParameterTypes());
// 根据目标方法对象获取注解对象
DeptCache deptCache = methodWithAnnotations.getDeclaredAnnotation(DeptCache.class);
// 解析key
String keyExpr = deptCache.keyExpr();
Object[] argValues = joinPoint.getArgs();
String key = parseKey(methodWithAnnotations, argValues, keyExpr);
//根据key查询缓存
String cache = findCache(key);
if (StringUtils.isNotBlank(cache)) {
return cache;
}
//执行目标方法
try {
result = joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return result;
}
/**
* 解析key(只支持String)
*
* @param method
* @param argValues 方法参数值
* @param keyExpr 注解值或表达式(含#)
* @return key
* @throws IllegalAccessException
*/
private String parseKey(Method method, Object[] argValues, String keyExpr) {
if (keyExpr.startsWith("#")) {
String[] exprParamNames = keyExpr.substring(keyExpr.indexOf('#') + 1).split("\\.");
// 获取方法参数名列表
LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
String[] paramNames = discoverer.getParameterNames(method);
Object argValue = null;
for (int i = 0; i < paramNames.length; i++) {
if (paramNames[i].equals(exprParamNames[0])) {
argValue = argValues[i];
break;
}
}
try {
for (int i = 1; i < exprParamNames.length; i++) {
argValue = dealArg(argValue, exprParamNames[i]);
}
if (argValue instanceof String) {
return (String) argValue;
}
} catch (IllegalAccessException e) {
log.info("keyExpr:{}" + keyExpr);
throw new RuntimeException("无法解析表达式:" + e.getMessage());
}
throw new RuntimeException("无法解析表达式");
} else {
return keyExpr;
}
}
private Object dealArg(Object object, String fieldName) throws IllegalAccessException {
if (object == null) {
return null;
}
Class clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//属性可见
field.setAccessible(true);
if (fieldName.equals(field.getName())) {
return field.get(object);
}
}
return null;
}
private String findCache(String key) {
double k = Math.random();
log.info("k======"+k);
if (k < 0.5) {
return key + "_lt_0.5";
}
return null;
}
@RequestMapping(value = "testDeptCache",method = RequestMethod.GET)
@DeptCache(keyExpr = "#user.nickname")
public String testDeptCache(User user) {
return "OK";
}
3.权限注解
/**
* 权限注解
*
* @author A.keung
* 2019/8/30 0030
*/
@Target({ ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionCheck {
String[] values() default {};
}
/**
* 权限注解拦截器
*
* @author A.keung
* 2019/8/30 0030
*/
public class PermissionCheckInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!handler.getClass().isAssignableFrom(HandlerMethod.class)) {
return true;
}
PermissionCheck permission = findPermissionCheck((HandlerMethod) handler);
//无权限注解
if (permission == null) {
return true;
}
//获取注解中的值
String[] values = permission.values();
//获取用户权限
Map<String, String> userPermission = findUserPermission();
for (String value : values) {
if (userPermission.containsKey(value)) {
return true;
}
}
throw new Exception("No Permission");
}
/**
* 模拟获取权限集
*
* @return 权限集
*/
private Map<String, String> findUserPermission() {
Map<String, String> permissionMap = new HashMap<>();
permissionMap.put("SELECT", "");
permissionMap.put("UPDATE", "");
permissionMap.put("DELETE", "");
return permissionMap;
}
/**
* 获取注解信息
*
* @param handlerMethod 方法对象
* @return PermissionCheck注解
*/
private PermissionCheck findPermissionCheck(HandlerMethod handlerMethod) {
//方法上注解
PermissionCheck permission = handlerMethod.getMethodAnnotation(PermissionCheck.class);
if (permission == null) {
//类上注解
permission = handlerMethod.getBeanType().getAnnotation(PermissionCheck.class);
}
return permission;
}
}
/**
* Mvc配置类
* 在SpringBoot2.0之后的版本中WebMvcConfigurerAdapter过时了
* 采用以下方式:
* 1.继承WebMvcConfigurationSupport类
* 静态资源的访问的问题,在静态资源的访问的过程中,
* SpringBoot中的自动的配置会失效,不需要返回逻辑视图,可以选择继承此类
* 继承WebMvcConfigurationSupport,若多个类继承该类,只会有一个类中的重写的方法执行
* 2.实现WebMvcConfigurer接口
* @author A.keung
* 2019/8/30 0030
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry interceptorRegistry) {
interceptorRegistry.addInterceptor(new PermissionCheckInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index/**","/api/login");
}
@Override
public void configurePathMatch(PathMatchConfigurer pathMatchConfigurer) {
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer contentNegotiationConfigurer) {
}
@Override
public void configureAsyncSupport(AsyncSupportConfigurer asyncSupportConfigurer) {
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer defaultServletHandlerConfigurer) {
}
@Override
public void addFormatters(FormatterRegistry formatterRegistry) {
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {
}
@Override
public void addCorsMappings(CorsRegistry corsRegistry) {
}
@Override
public void addViewControllers(ViewControllerRegistry viewControllerRegistry) {
}
@Override
public void configureViewResolvers(ViewResolverRegistry viewResolverRegistry) {
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> list) {
}
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> list) {
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> list) {
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> list) {
}
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> list) {
}
@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> list) {
}
@Override
public Validator getValidator() {
return null;
}
@Override
public MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
@PermissionCheck(values = "SELECT")
@RequestMapping(value = "testPermissionCheck",method = RequestMethod.GET)
public String testPermissionCheck() {
return "OK";
}