feat(Java_SpringExample): AspectJ代码提交,代码报错未解决

This commit is contained in:
huangzj
2020-05-26 21:57:55 +08:00
parent 456f0be8b5
commit e65411be30
24 changed files with 852 additions and 18 deletions
+2
View File
@@ -2,3 +2,5 @@
##更新记录
2020/5/22 : 创建工程(代码有问题,先提交)
2020/5/26 : AspectJ代码提交,代码报错未解决
+55
View File
@@ -0,0 +1,55 @@
package Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/**
* @author : selfimpr
* @description :整理文件添加注解,通过aspectj进行切面注入
* @date : 2017/11/11 21:28
*/
@Aspect
public class AopTestClass {
@Before("execution(* service.MainServiceImpl.*(..))")
public void begin(){
System.out.println("表演开始");
}
@After("execution(* service.MainServiceImpl.*(..))")
public void end(){
System.out.println("表演结束");
}
/**
* 通过这个声明来实现环绕通知,所谓的环绕通知就是说在在一个方法中规定了类运行几个状态直接的通知事件
* 可以这样声明来实现不用写一大串的代码
*/
@Pointcut("execution(* service.MainServiceImpl.*(..))")
public void perform(){}
@Around("perform()")
public void AroundAop(ProceedingJoinPoint proceedingJoinPoint){
try{
System.out.println("我在程序运行之前进行了通知");
//这个方法代表被切接口进行执行,上面的方法表示之前执行,下面的方法表示之后执行
proceedingJoinPoint.proceed();
System.out.println("我在程序运行之后进行了通知");
}catch(Throwable throwable){//抛出错误的时候进行aop通知
throwable.printStackTrace();
System.out.println("运行错误产生的aop通知");
}
}
/**
* 这个是测试有传参的Aop接口环绕
* @param testNum 入参,根据方法决定入参的数量与类型
*/
@Pointcut("execution(* service.MainServiceImpl.testAopParam(int)) && args(testNum)")
public void testAopParams(int testNum){
}
@After("testAopParams(testNum)")
public void testHasParam(int testNum){
System.out.println(testNum);
}
}
@@ -0,0 +1,37 @@
package Aspect;
import annotation.AopGetClassMessage;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 测试通过切片的方式获取到类的属性方法等信息
* @author 志军
*/
@Aspect
public class GetClassMessageAop {
/**
* 参考地址 https://www.cnblogs.com/qiumingcheng/p/5923928.html
*/
@Around("execution(* controller.*.*(..)) && @annotation(aopAnnotation)")
public Object getClassMessage(ProceedingJoinPoint pjp, AopGetClassMessage aopAnnotation) throws Throwable {
System.out.println("拦截到了" + pjp.getSignature().getName() + "方法...");
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method targetMethod = methodSignature.getMethod();
Class clazz = targetMethod.getClass();
System.out.printf("类的名称:%s,方法名称:%s,注解的说明:%s\n", pjp.getSignature().getName(), targetMethod.getName(), aopAnnotation.use());
System.out.println("类的信息:"+clazz.getName()+"所有方法:"+ Arrays.toString(clazz.getMethods()));
return pjp.proceed();
}
}
+34
View File
@@ -0,0 +1,34 @@
package Aspect;
import annotation.Sensitive;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* 这个aop是为了处理敏感词汇注解自动解析处理的
* @author 志军
*/
@Aspect
public class SensitiveAop {
/**
* spring可以直接对加了注解的方法进行处理
*/
@Before(value = "@annotation(annotation.SensitiveParam)")
public void begin() {
System.out.println("表演开始");
}
/**
* 在Controller层进行注解的拦截(敏感词汇处理)
*/
@Around("execution(* controller.*.*(..)) && @annotation(sensitive)")
public Object getClassMessage(ProceedingJoinPoint pjp, Sensitive sensitive) {
}
}
@@ -0,0 +1,17 @@
package annotation;
import java.lang.annotation.*;
/**
* 测试通过切片的方式获取到类的属性方法等信息
* @author 志军
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD,ElementType.FIELD})
@Documented
@Inherited //可以继承
public @interface AopGetClassMessage {
String use() default "没写";
}
+12
View File
@@ -0,0 +1,12 @@
package annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD,ElementType.FIELD})
@Documented
public @interface InTest {
}
+22
View File
@@ -0,0 +1,22 @@
package annotation;
import java.lang.annotation.*;
/**
* 在方法上标识是否进行敏感词处理。
* 这边这个注解主要是配合Aop去拦截
* 这边拦截之后只会处理方法的出参数,这边敏感词约定就是处理出参
* @author 志军
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
@Documented
@Inherited //可以继承
public @interface Sensitive {
/**
* 是否进行参数的敏感处理
*/
boolean process() default true;
}
@@ -0,0 +1,29 @@
package annotation;
import logic.sensitive.SensitiveRule;
import logic.sensitive.StringRule;
import java.lang.annotation.*;
/**
* 是否对出参的词汇进行敏感词处理
* @author 志军
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.FIELD})
@Documented
@Inherited //可以继承
public @interface SensitiveParam {
/**
* 是否处理
*/
boolean process() default true;
/**
* 处理规则
*/
Class<? extends SensitiveRule> rule() default StringRule.class;
}
@@ -1,8 +1,8 @@
package config;
import com.springmvc.config.aop.SensitiveAop;
import com.springmvc.config.aop.aopClass;
import com.springmvc.config.support.RequestLimitAspect;
import Aspect.AopTestClass;
import Aspect.SensitiveAop;
import logic.requestLimit.RequestLimitAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@@ -11,23 +11,33 @@ import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* Created by Administrator on 2017/7/26.
* 启动AspectJ自动代理
* @author 志军
*/
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class AopComponentLoder {
public class AopComponentLoader {
//在这里注册切面的bean
/**
* 通过这个类开启EnableAspectJAutoProxy注解
* 在这边注册切面类,比较统一不会把切面类弄得到处都是不好找
*/
@Bean
public aopClass aopClass() {
return new aopClass();
public AopTestClass aopClass() {
return new AopTestClass();
}
/**
* 敏感词汇限制转换
*/
@Bean
public SensitiveAop sensitiveAop() {
return new SensitiveAop();
}
/**
* 接口访问频率限制
*/
@Bean
public RequestLimitAspect getRequestLimitAspect() {
return new RequestLimitAspect();
@@ -0,0 +1,31 @@
package controller;
import annotation.Sensitive;
import logic.sensitive.SensitiveObject;
import logic.sensitive.Test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* 切面测试类
* @author 志军
*/
@Controller
public class AspectController {
@RequestMapping(value = "/aop/sensitive", method = RequestMethod.GET)
@Sensitive
public SensitiveObject testSensitive(){
SensitiveObject sensitiveObject = new SensitiveObject();
sensitiveObject.setPhone("1820000000000");
sensitiveObject.setNoPhone("1820000000000");
Test test = new Test();
test.setPhone("1820000000000");
test.setNum(1);
test.setEmail("8515@qq.com");
sensitiveObject.setTest(test);
return sensitiveObject;
}
}
@@ -0,0 +1,32 @@
package controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import service.MainService;
@Controller
public class MainController {
@Autowired
private MainService mainService;
@RequestMapping(value = "/test/aop/param", method = RequestMethod.GET)
public void testAopParam(){
mainService.testAopParam(1);
}
@RequestMapping(value = "/test/aop", method = RequestMethod.GET)
public void testAop(){
mainService.testAop();
}
@RequestMapping(value = "/test/aop/getClassMessage", method = RequestMethod.GET)
public void getClassMessage(){
System.out.println("测试通过Aop配合接口获取类的信息");
}
}
@@ -1,13 +1,4 @@
/*
* @(#) SessionListenerTask
* 版权声明 网宿科技, 版权所有 违者必究
*
* <br> Copyright: Copyright (c) 2018
* <br> Company:网宿科技
* <br> @author Administrator
* <br> @description 功能描述
* <br> 2018-11-13 20:32:51
*/
package listener;
@@ -0,0 +1,33 @@
package logic.requestLimit;
import java.lang.annotation.*;
/**
* 限制60秒内访问10次,之后等待300秒(时间可以自定义)
*
* @author huangzj1
* @date 2018-12-16 17:07
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
@Documented
@Inherited //可以继承
public @interface RequestLimit {
/**
* 多少时间内
*/
int time() default 60;
/**
* 超过多少次数
*/
int count() default 10;
/**
* 超过之后等待
*/
int waits() default 300;
}
@@ -0,0 +1,83 @@
package logic.requestLimit;
import com.itextpdf.text.log.Logger;
import com.itextpdf.text.log.LoggerFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import util.DateTimeUtil;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* ${DESCRIPTION}
*
* @author huangzj1
* @date 2018-12-16 17:10
*/
@Aspect
public class RequestLimitAspect {
private static final Logger logger = LoggerFactory.getLogger("RequestLimitLogger");
private static final Map<String, RequestLimitBody> URL_MAP = new ConcurrentHashMap<>();
@Before(value = "@annotation(limit) &&args(request)")
public void requestLimit(JoinPoint joinPoint, HttpServletRequest request, RequestLimit limit) throws RequestLimitException {
try {
if (request == null) {
throw new RequestLimitException("方法中缺失HttpServletRequest参数");
}
if(limit.waits()<limit.time()){
throw new RequestLimitException("程序错误,延时时间不能小于规定时间");
}
//其实这边还应该加上一个客户端的ip或者登录用户来做标识,但是我这边没做
String key = "req_limit_".concat(joinPoint.getSignature().getName());
RequestLimitBody body = URL_MAP.get(key);
if (body == null) {
body = new RequestLimitBody();
body.setClickCount(1);
body.setLastClick(DateTimeUtil.getNowSeconds());
URL_MAP.put(key, body);
return;
}
//如果点击超过次数,延迟点击,并且还没到达时间。
if (body.getDelayClickUtilTIme() != null && DateTimeUtil.getNowSeconds() - body.getDelayClickUtilTIme() <= limit.waits()) {
System.out.println("超过点击次数,还需要等待" + (limit.waits() - (DateTimeUtil.getNowSeconds() - body.getDelayClickUtilTIme())) + "");
throw new RequestLimitException("超过点击次数,还需要等待" + (limit.waits() - (DateTimeUtil.getNowSeconds() - body.getDelayClickUtilTIme())) + "");
}else{
}
//如果最后一次点击在规定时间之内并且点击次数超过规定点击次数.进入延迟点击
if (DateTimeUtil.getNowSeconds() - body.getLastClick() < limit.time() && body.getClickCount() >= limit.count()) {
body.setDelayClickUtilTIme(DateTimeUtil.getNowSeconds());
System.out.println("暂时不可点击,需等待" + limit.waits() + "");
throw new RequestLimitException("暂时不可点击,需等待" + limit.waits() + "");
}
//如果第一次点击到最后一次点击超过了规定时间重置(前提是前面的都要不满足)
if (DateTimeUtil.getNowSeconds() - body.getLastClick() > limit.time()) {
body.setClickCount(1);
body.setLastClick(DateTimeUtil.getNowSeconds());
URL_MAP.put(key, body);
return;
}
//没有超过时间要加1
body.setClickCount(body.getClickCount() + 1);
} catch (RequestLimitException e) {
throw e;
} catch (Exception e) {
logger.error("发生异常: ", e);
}
}
}
@@ -0,0 +1,45 @@
package logic.requestLimit;
public class RequestLimitBody {
/**
* 点击次数
*/
private Integer clickCount;
/**
* 上一次操作的时间点
*/
private long lastClick;
/**
* 设置延迟点击的最后时间点
*/
private Long delayClickUtilTIme;
public Long getDelayClickUtilTIme() {
return delayClickUtilTIme;
}
public void setDelayClickUtilTIme(Long delayClickUtilTIme) {
this.delayClickUtilTIme = delayClickUtilTIme;
}
public Integer getClickCount() {
return clickCount;
}
public void setClickCount(Integer clickCount) {
this.clickCount = clickCount;
}
public long getLastClick() {
return lastClick;
}
public void setLastClick(long lastClick) {
this.lastClick = lastClick;
}
}
@@ -0,0 +1,22 @@
package logic.requestLimit;
/**
* ${DESCRIPTION}
*
* @author huangzj1
* @date 2018-12-16 17:17
*/
public class RequestLimitException extends Exception {
private static final long serialVersionUID = 1364225358754654702L;
public RequestLimitException() {
super("HTTP请求超出设定的限制");
}
public RequestLimitException(String message) {
super(message);
}
}
@@ -0,0 +1,24 @@
package logic.sensitive;
import org.apache.commons.lang3.StringUtils;
/**
* 这边是一个关于Test类的处理规则,最好是对所有的类型进行细分
* @author 志军
*/
public class ObjectRule implements SensitiveRule<Test>{
@Override
public Test process(Test test) {
if (test !=null){
if(StringUtils.isNotBlank(test.getPhone())){
test.setPhone(test.getPhone().charAt(0) + "XXX" + test.getPhone().charAt(test.getPhone().length()-1));
}
if(StringUtils.isNotBlank(test.getEmail())){
test.setEmail(test.getEmail().charAt(0) + "XXX" + test.getEmail().charAt(test.getEmail().length()-1));
}
}
return null;
}
}
@@ -0,0 +1,39 @@
package logic.sensitive;
import annotation.SensitiveParam;
public class SensitiveObject {
@SensitiveParam
private String Phone;
@SensitiveParam(process = false)
private String noPhone;
@SensitiveParam(rule = ObjectRule.class)
private Test test;
public String getPhone() {
return Phone;
}
public void setPhone(String phone) {
Phone = phone;
}
public String getNoPhone() {
return noPhone;
}
public void setNoPhone(String noPhone) {
this.noPhone = noPhone;
}
public Test getTest() {
return test;
}
public void setTest(Test test) {
this.test = test;
}
}
@@ -0,0 +1,14 @@
package logic.sensitive;
/**
* @author 志军
* @description 敏感词汇处理规则
* @param <T> 处理的类型
*/
public interface SensitiveRule<T> {
/**
* 自定义类型处理规则
*/
T process(T t);
}
@@ -0,0 +1,17 @@
package logic.sensitive;
import org.apache.commons.lang3.StringUtils;
/**
* 这边是一个通用的String处理规则,也可以分来对不同的String进行处理,比如说电话怎么处理,邮箱怎么处理
*/
public class StringRule implements SensitiveRule<String>{
@Override
public String process(String s) {
if(StringUtils.isNotBlank(s)){
s = s.charAt(0) + "XXX" + s.charAt(s.length()-1);
}
return s;
}
}
+35
View File
@@ -0,0 +1,35 @@
package logic.sensitive;
public class Test {
private String phone;
private int num;
private String email;
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
+13
View File
@@ -0,0 +1,13 @@
package service;
/**
* Created by Administrator on 2017/7/18.
* @author 志军
*/
public interface MainService {
String testAopParam(int a);
void testAop();
}
@@ -0,0 +1,26 @@
package service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Created by Administrator on 2017/7/18.
* @author 志军
*/
@Service
@Transactional
public class MainServiceImpl implements MainService {
@Override
public String testAopParam(int a) {
return String.valueOf(a);
}
@Override
public void testAop() {
System.out.println("测试Aop");
}
}
+211
View File
@@ -0,0 +1,211 @@
package util;
import org.springframework.util.Assert;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.TimeZone;
public class DateTimeUtil {
public static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
public static final String DEFAULT_TIME_PATTERN = "HH:mm:ss";
public static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static final String DEFAULT_PATTERN_CLOSE = "yyyyMMddHHmmss";
public static final String DATE_TIME_MINUTE_PATTERN = "yyyy-MM-dd HH:mm";
public static final String ISO_8601_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ";
public static final String lOG_PARAM_TIME_PATTERN = "yyyy-MM-dd-HHmm";
/**
* 获取当天日期,"yyyy-MM-dd"
*/
public static String getCurrentDate() {
return LocalDate.now().toString();
}
/**
* 获取当前时间,yyyy-MM-dd HH:mm:ss
*/
public static String getCurrentDateTime() {
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(DEFAULT_PATTERN));
}
/**
* 获取与所给日期间隔要求天数的日期
* @param localDate 参考日期, yyyy-MM-dd
* @param dayOffset 间隔天数
*/
public static String plusDay(final String localDate, final int dayOffset) {
Assert.isTrue(dayOffset >= 0, "偏移量必须大于0");
return LocalDate.parse(localDate).plusDays(dayOffset).format(DateTimeFormatter.ISO_LOCAL_DATE);
}
/**
* 获取与所给日期间隔要求天数的日期
* @param localDate 参考日期, yyyy-MM-dd
* @param dayOffset 间隔天数
*/
public static String minusDay(final String localDate, final int dayOffset) {
Assert.isTrue(dayOffset >= 0, "偏移量必须大于0");
return LocalDate.parse(localDate).minusDays(dayOffset).format(DateTimeFormatter.ISO_LOCAL_DATE);
}
/**
* 将日期时间转换成指定格式的时间
*/
public static String dateToString(String pattern, LocalDateTime dateTime) {
return DateTimeFormatter.ofPattern(pattern).format(dateTime);
}
/**
* 时间戳转换为指定格式字符串(秒)
*/
public static String dateToString(String pattern, long epochSecond, TimeZone timeZone) {
return dateToString(pattern, LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), timeZone.toZoneId()));
}
/**
* 时间戳转成指定格式字符串(毫秒)
*/
public static String timestampToString(String pattern, long timestamp, TimeZone timeZone) {
return dateToString(pattern, LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), timeZone.toZoneId()));
}
public static String dateToString(String pattern, ZonedDateTime dateTime) {
return DateTimeFormatter.ofPattern(pattern)
.format(dateTime);
}
/**
* 将LocalDateTime转换成指定格式字符串
*/
public static String localTimeToString(LocalDateTime localDateTime, String pattern) {
LocalTime localTime = localDateTime.toLocalTime();
return DateTimeFormatter.ofPattern(pattern).format(localTime);
}
/**
* 将时间格式换成"HH:mm:ss" 格式
*/
public static String formatDateToTime(LocalDateTime date) {
return DateTimeUtil.dateToString(DEFAULT_TIME_PATTERN, date);
}
/**
* 将时间格式换成"yyyy-MM-dd" 格式
*/
public static String formatDateToDay(LocalDateTime date) {
return DateTimeUtil.dateToString(DEFAULT_DATE_PATTERN, date);
}
/**
* @param timeString yyyy-MM-dd-HHmm
* @return yyyy-MM-dd HH:mm 格式的时间字符串
*/
public static String paramTimeFormat(String timeString) throws ParseException {
Date newDate = new SimpleDateFormat(lOG_PARAM_TIME_PATTERN).parse(timeString);
return new SimpleDateFormat(DATE_TIME_MINUTE_PATTERN).format(newDate);
}
/**
* 获取当前时间,yyyy-MM-dd HH:mm:ss
* 注意:使用当前系统默认的时区
*/
public static LocalDateTime getNow() {
return LocalDateTime.now();
}
/**
* 将时间戳(单位:毫秒)转成 LocalDateTime
*/
public static LocalDateTime timeStampToLocalDateTime(long timeStamp) {
return Instant.ofEpochMilli(timeStamp).atZone(ZoneId.systemDefault()).toLocalDateTime();
}
/**
* 将时间戳(单位为:秒)转成 LocalDateTime
*/
public static LocalDateTime epochSecondToLocalDateTime(long epochSecond, TimeZone timeZone) {
return epochSecondToLocalDateTime(epochSecond, timeZone.toZoneId());
}
/**
* 将时间戳(单位为:秒)转成 LocalDateTime
*/
public static LocalDateTime epochSecondToLocalDateTime(long epochSecond, ZoneId zoneId) {
return Instant.ofEpochSecond(epochSecond).atZone(zoneId).toLocalDateTime();
}
/**
* LocalDateTime转成时间戳:毫秒
*/
public static long toEpochMilli(LocalDateTime localDateTime, TimeZone timeZone) {
return Instant.from(localDateTime.atZone(timeZone.toZoneId())).toEpochMilli();
}
/**
* 将字符串转换为LocalDateTime
*/
public static LocalDateTime stringToLocalDateTime(String dateStr, String pattern) {
DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
return LocalDateTime.parse(dateStr, df);
}
/**
* 到天的字符串,转成LocalDateTime
* @param dayStr 如"2017-11-16"
* @return 返回0点0分0秒的时间 如 "2017-11-16 00:00:00"
*/
public static LocalDateTime dayStringToLocalDateTime(String dayStr) {
return LocalDate.parse(dayStr, DateTimeFormatter.ofPattern(DEFAULT_DATE_PATTERN)).atTime(0, 0, 0);
}
/**
* LocalDateTime转成时间戳:秒
*/
public static long toEpochSecond(LocalDateTime localDateTime, TimeZone timeZone) {
return Instant.from(localDateTime.atZone(timeZone.toZoneId())).getEpochSecond();
}
public static long toEpochSecond(LocalDateTime localDateTime, ZoneId zoneId) {
return localDateTime.atZone(zoneId).toEpochSecond();
}
/**
* 获取当前时间的秒数
*/
public static long getNowSeconds(){
return
LocalDateTime.now().toEpochSecond(ZoneOffset.MAX);
}
/**
* 是否同一个时间点
*/
public static boolean isTheSameDay(LocalDateTime startDate, LocalDateTime endDate) {
return startDate.toLocalDate()
.isEqual(endDate.toLocalDate());
}
/**
* LocalDateTime 转成时间戳
*/
public static Instant toInstant(LocalDateTime endDate, TimeZone timeZone) {
return endDate.atZone(timeZone.toZoneId()).toInstant();
}
}