精华内容
下载资源
问答
  • 2020CIS基于安全切面实现银行级默认安全 漏洞检测
  • 什么是基于注解的切面实现

    千次阅读 2017-12-05 19:51:06
    什么是基于注解的切面实现我们使用切面来非侵入式操作程序方法,常用的场景如日志记录、权限判断等。 下面我实现权限判断的切面。分析: 要实现基于注解的切面,我们要定义“注解”,定义切面,定义权限验证,定义...

    什么是基于注解的切面实现

    我们使用切面来非侵入式操作程序方法,常用的场景如日志记录、权限判断等。
    下面我实现权限判断的切面。

    分析:
    要实现基于注解的切面,我们要定义“注解”,定义切面,定义权限验证,定义权限返回。

    1. 定义注解:PermissionCheck.java
    @Target({ElementType.TYPE, ElementType.METHOD}) // 注解类型, 级别
    @Retention(RetentionPolicy.RUNTIME) // 运行时注解
    public @interface PermissionCheck {
    
        String value() default "";
    
    }
    
    1. 定义权限校验方法,这里定义 AuthService 和它的实现。
    public interface AuthService {
    
        boolean checkAccess();
    }
    
    
    @Service
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public class AuthServiceImpl implements AuthService {
    
    
        @Override
        public boolean checkAccess() {
            return true;
        }
    }
    

    根据需要可改写 checkAccess 方法。

    1. 定义一个advice 来处理校验结果:
    @ControllerAdvice
    public class PermissionAdvice {
    
        @ExceptionHandler(value = PermissionCheckException.class)
        @ResponseStatus(HttpStatus.OK)
        @ResponseBody
        public String dealWithPermissionCheckException(PermissionCheckException exception) {
            System.out.println(exception.getMessage());
            return exception.getMessage();
        }
    
    
        public String dealWithPermissionCheckException() {
    
            return null;
        }
    }
    
    
    1. 接下来就是组合进切面了
    @Aspect // 切面标识
    @Component // 交给spring容器管理
    public class PermissionAspect {
    
        @Autowired
        private AuthService authService;
    
        /**
         * 选取切入点为自定义注解
         */
        @Pointcut("@annotation(com.honeywen.credit.annotation.PermissionCheck)")
        public void permissionCheck(){}
    
    
        @Before(value = "permissionCheck()")
        public void before(JoinPoint joinPoint) throws NoSuchMethodException {
            // 获取连接点的方法签名对象
            Signature signature = joinPoint.getSignature();
            if (!(signature instanceof MethodSignature)) {
                throw new PermissionCheckException("user permission check failed , stop the request!");
    
            }
            MethodSignature methodSignature = (MethodSignature) signature;
            Object target = joinPoint.getTarget();
            // 获取到当前执行的方法
            Method method = target.getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
            // 获取方法的注解
            PermissionCheck annotation = method.getAnnotation(PermissionCheck.class);
            System.out.println(annotation);
            System.out.println("我是在执行业务逻辑之前");
            // 权限检查
            authService.checkAccess();
    
    
    
        }
    
        @After(value = "permissionCheck()")
        public void after(JoinPoint joinPoint) {
            System.out.println("我是在执行业务逻辑之后");
    
        }
    
    
    
    
    }
    

    总结:
    主要过程在定义切面, 然后就是切面在哪里执行:

        @Pointcut("@annotation(com.honeywen.credit.annotation.PermissionCheck)")
        public void permissionCheck(){}

    这里声明的是标注 @PermissionCheck 注解的方法执行。

    展开全文
  • 通过springboot的Aop面向切面实现彩色日志使用的场景 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员...

    通过springboot的Aop面向切面实现彩色日志使用的场景

    Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
    在项目中我们脱离不开保留用户访问的相关信息,那么下文我们来一起实现springboot通过Aop面向切面实现彩色日志。

    • 我们在项目的resources文件夹下新建一个日志的配置文件命名为logback.xml

      logback.xml彩色日志是每天保留不同等级日志以及会记录实时日志内容,同时会将保存的内容打印在控制台,日志保留的有效期是15天,可自行配置,超过设置的天数会自动删除16天前的日志文件,其次保存的位置也可以自行配置

      	<?xml version="1.0" encoding="UTF-8"?>
      	<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
      	<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
      	<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
      	<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false-->
      	<configuration  scan="true" scanPeriod="10 seconds">
      	
      	    <!--<include resource="org/springframework/boot/logging/logback/base.xml" />-->
      	
      	    <contextName>logback</contextName>
      	    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
      	    <property name="log.path" value="D:/mylogs/logs" /><!--D:/mylogs/logs-->
      	
      	    <!-- 彩色日志 -->
      	    <!-- 彩色日志依赖的渲染类 -->
      	    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
      	    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
      	    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
      	    <!-- 彩色日志格式 -->
      	    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
      	
      	
      	    <!--输出到控制台-->
      	    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
      	        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
      	        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      	            <level>info</level>
      	        </filter>
      	        <encoder>
      	            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
      	            <!-- 设置字符集 -->
      	            <charset>UTF-8</charset>
      	        </encoder>
      	    </appender>
      	
      	
      	    <!--输出到文件-->
      	
      	    <!-- 时间滚动输出 level为 DEBUG 日志 -->
      	    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      	        <!-- 正在记录的日志文件的路径及文件名 -->
      	        <file>${log.path}/log_debug.log</file>
      	        <!--日志文件输出格式-->
      	        <encoder>
      	            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      	            <charset>UTF-8</charset> <!-- 设置字符集 -->
      	        </encoder>
      	        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      	        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      	            <!-- 日志归档 -->
      	            <fileNamePattern>${log.path}/debug/log-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      	            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
      	                <maxFileSize>100MB</maxFileSize>
      	            </timeBasedFileNamingAndTriggeringPolicy>
      	            <!--日志文件保留天数-->
      	            <maxHistory>15</maxHistory>
      	        </rollingPolicy>
      	        <!-- 此日志文件只记录debug级别的 -->
      	        <filter class="ch.qos.logback.classic.filter.LevelFilter">
      	            <level>debug</level>
      	            <onMatch>ACCEPT</onMatch>
      	            <onMismatch>DENY</onMismatch>
      	        </filter>
      	    </appender>
      	
      	    <!-- 时间滚动输出 level为 INFO 日志 -->
      	    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      	        <!-- 正在记录的日志文件的路径及文件名 -->
      	        <file>${log.path}/log_info.log</file>
      	        <!--日志文件输出格式-->
      	        <encoder>
      	            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      	            <charset>UTF-8</charset>
      	        </encoder>
      	        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      	        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      	            <!-- 每天日志归档路径以及格式 -->
      	            <fileNamePattern>${log.path}/info/log-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      	            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
      	                <maxFileSize>100MB</maxFileSize>
      	            </timeBasedFileNamingAndTriggeringPolicy>
      	            <!--日志文件保留天数-->
      	            <maxHistory>15</maxHistory>
      	        </rollingPolicy>
      	        <!-- 此日志文件只记录info级别的 -->
      	        <filter class="ch.qos.logback.classic.filter.LevelFilter">
      	            <level>info</level>
      	            <onMatch>ACCEPT</onMatch>
      	            <onMismatch>DENY</onMismatch>
      	        </filter>
      	    </appender>
      	
      	    <!-- 时间滚动输出 level为 WARN 日志 -->
      	    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      	        <!-- 正在记录的日志文件的路径及文件名 -->
      	        <file>${log.path}/log_warn.log</file>
      	        <!--日志文件输出格式-->
      	        <encoder>
      	            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      	            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
      	        </encoder>
      	        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      	        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      	            <fileNamePattern>${log.path}/warn/log-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      	            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
      	                <maxFileSize>100MB</maxFileSize>
      	            </timeBasedFileNamingAndTriggeringPolicy>
      	            <!--日志文件保留天数-->
      	            <maxHistory>15</maxHistory>
      	        </rollingPolicy>
      	        <!-- 此日志文件只记录warn级别的 -->
      	        <filter class="ch.qos.logback.classic.filter.LevelFilter">
      	            <level>warn</level>
      	            <onMatch>ACCEPT</onMatch>
      	            <onMismatch>DENY</onMismatch>
      	        </filter>
      	    </appender>
      	
      	
      	    <!-- 时间滚动输出 level为 ERROR 日志 -->
      	    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      	        <!-- 正在记录的日志文件的路径及文件名 -->
      	        <file>${log.path}/log_error.log</file>
      	        <!--日志文件输出格式-->
      	        <encoder>
      	            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      	            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
      	        </encoder>
      	        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
      	        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      	            <fileNamePattern>${log.path}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
      	            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
      	                <maxFileSize>100MB</maxFileSize>
      	            </timeBasedFileNamingAndTriggeringPolicy>
      	            <!--日志文件保留天数-->
      	            <maxHistory>15</maxHistory>
      	        </rollingPolicy>
      	        <!-- 此日志文件只记录ERROR级别的 -->
      	        <filter class="ch.qos.logback.classic.filter.LevelFilter">
      	            <level>ERROR</level>
      	            <onMatch>ACCEPT</onMatch>
      	            <onMismatch>DENY</onMismatch>
      	        </filter>
      	    </appender>
      	
      	    <!--
      	        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
      	        以及指定<appender><logger>仅有一个name属性,
      	        一个可选的level和一个可选的addtivity属性。
      	        name:用来指定受此logger约束的某一个包或者具体的某一个类。
      	        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
      	              还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
      	              如果未设置此属性,那么当前logger将会继承上级的级别。
      	        addtivity:是否向上级logger传递打印信息。默认是true-->
      	    <!--<logger name="org.springframework.web" level="info"/>-->
      	    <!--<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>-->
      	    <!--
      	        使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
      	        第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
      	        第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
      	     -->
      	
      	
      	    <!--
      	        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
      	        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
      	        不能设置为INHERITED或者同义词NULL。默认是DEBUG
      	        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
      	    -->
      	
      	    <!--开发环境:打印控制台-->
      	    <springProfile name="dev">
      	        <logger name="com.nmys.view" level="debug"/>
      	    </springProfile>
      	
      	    <root level="info">
      	        <appender-ref ref="CONSOLE" />
      	        <appender-ref ref="DEBUG_FILE" />
      	        <appender-ref ref="INFO_FILE" />
      	        <appender-ref ref="WARN_FILE" />
      	        <appender-ref ref="ERROR_FILE" />
      	    </root>
      	
      	    <!--生产环境:输出到文件-->
      	    <!--<springProfile name="pro">-->
      	    <!--<root level="info">-->
      	    <!--<appender-ref ref="CONSOLE" />-->
      	    <!--<appender-ref ref="DEBUG_FILE" />-->
      	    <!--<appender-ref ref="INFO_FILE" />-->
      	    <!--<appender-ref ref="ERROR_FILE" />-->
      	    <!--<appender-ref ref="WARN_FILE" />-->
      	    <!--</root>-->
      	    <!--</springProfile>-->
      	
      	</configuration>
      	```
      
      
    • 创建一个Aop切面类

      @Target({ElementType.PARAMETER, ElementType.METHOD})
      @Retention(RetentionPolicy.RUNTIME)
      @Inherited
      @Documented
      public @interface Operation {
          String name();
      }
      
      @Aspect // FOR AOP
      @Order(-99) // 控制多个Aspect的执行顺序,越小越先执行
      @Component
      public class LogAspect {
          private Logger logger = LoggerFactory.getLogger(getClass());
      
          @Pointcut("@annotation(xxx.xxxxx.Operation)")//上述Operation类的路径地址
          public void method(){
          }
      
          /**
           * doAround:(环绕方法,统一日志处理). <br/>
           * @author fenglanglang
           * @param joinPoint
           * @return
           * @throws Throwable
           */
          @Around("method()")
          public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
              long beginTime = System.currentTimeMillis();//1、开始时间
              Date date=new Date();
              ServletRequestAttributes requestAttr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
              String uri = requestAttr.getRequest().getRequestURI();
              String method=requestAttr.getRequest().getMethod();//请求方式
              String contentType=requestAttr.getRequest().getContentType();//请求类型
              String url="" + requestAttr.getRequest().getServerName() //服务器地址
                      + ":"
                      + requestAttr.getRequest().getServerPort()           //端口号
                      + requestAttr.getRequest().getRequestURI();//接口名称00
              String queryurl="";
              Enumeration queryurls=requestAttr.getRequest().getParameterNames();
              ArrayList<String> arrayList=Collections.list(queryurls);
              String[] arrStr = arrayList.toArray(new String[0]);
              for (int asd=0;asd<arrStr.length;asd++){
                  String value=requestAttr.getRequest().getParameter(arrStr[asd]);
                  queryurl+=arrStr[asd]+"="+(value)+",";//获取url地址和参数
      //            System.out.println(arrStr[asd]+"="+(value));
              }
              String qstitile=afterReturning(joinPoint);
              //访问目标方法的参数 可动态改变参数值
              Object[] args = joinPoint.getArgs();
              //方法名获取
              String methodName = joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName();
              //可能在反向代理请求进来时,获取的IP存在不正确行 这里直接摘抄一段来自网上获取ip的代码
              //调用实际方法
              Object object = joinPoint.proceed();
              long endTime = System.currentTimeMillis()-beginTime;
              String ip=getIpAddr(requestAttr.getRequest());
              String content=
                      "\n"+qstitile+
                       "\n    请求用户:"+"可根据自己需求获取返回"+
                       ",\n    请求URL:"+url+
                       ",\n    请求方式:"+method+
                       ",\n    请求时间:"+date+
                       ",\n    请求参数: {"+queryurl+"}"+
                       ",\n    请求类型:"+contentType+
                       ",\n    请求ip:"+ip+
                       ",\n    返回状态:"+"可根据自己需求获取返回"+
                       ",\n    返回说明:"+"可根据自己需求获取返回"+
                       ",\n    结束总耗时:"+endTime+"毫秒"+
                       ",\n    返回的结果:"+object.toString()+
                       "\n----------------------\n";
              logger.info(content);
              return object;
          }
      
      
      
          /**
           *
           * getIpAddr:(获取ip)
           * @author fenglanglang
           * @param request
           * @return
           */
          public static String getIpAddr(HttpServletRequest request) {
              String ipAddress = null;
              try {
                  ipAddress = request.getHeader("x-forwarded-for");
                  if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                      ipAddress = request.getHeader("Proxy-Client-IP");
                  }
                  if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                      ipAddress = request.getHeader("WL-Proxy-Client-IP");
                  }
                  if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                      ipAddress = request.getRemoteAddr();
                      if (ipAddress.equals("127.0.0.1")) {
                          // 根据网卡取本机配置的IP
                          InetAddress inet = null;
                          try {
                              inet = InetAddress.getLocalHost();
                          } catch (UnknownHostException e) {
                              System.out.println("获取ip异常:{}" + Throwables.getStackTraceAsString(e));
                          }
                          ipAddress = inet.getHostAddress();
                      }
                  }
                  // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
                  if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
                      if (ipAddress.indexOf(",") > 0) {
                          ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                      }
                  }
              } catch (Exception e) {
                  ipAddress = "";
              }
              return ipAddress;
          }
      
      
          /**
           * 获取类名
           * @param joinPoint
           * @return
           */
          public String afterReturning(JoinPoint joinPoint){
              Class<? extends Object> clazz =  joinPoint.getTarget().getClass();
              String controllerOperation = clazz.getName();
              if(clazz.isAnnotationPresent(Operation.class)){
                  // 当前controller操作的名称
                  controllerOperation = clazz.getAnnotation(Operation.class).name();
              }
              // 获取当前方法
              MethodSignature signature = (MethodSignature) joinPoint.getSignature();
              Method method = signature.getMethod();
              // clazz类下的所有方法
              Method[] methods = clazz.getDeclaredMethods();
              String methodOperation = "";
              for (Method m : methods) {
                  if(m.equals(method)){
                      methodOperation = m.getName();
                      if(m.isAnnotationPresent(Operation.class)){
                          methodOperation = m.getAnnotation(Operation.class).name();
                      }
                  }
              }
              controllerOperation=controllerOperation.substring(controllerOperation.lastIndexOf(".")+1,controllerOperation.length());
              return "---------执行了"+controllerOperation+"下的"+methodOperation+"操作:---------";
          }
      }
      
      
    • 通过切面日志的应用

      在方法的类注解中直接引入切面@Operation(name = “读取文档内容”)即可

      	/**
      	     * 读取信息文本文档
      	     * @return
      	     * @throws Exception
      	     */
      	    @Operation(name = "读取文档内容")
      	    @RequestMapping(value = {"/filetext"})
      	    public ModelAndView filetext(String name, ReturnVo returnVo) throws Exception{
      	        return new ModelAndView("before/public/filetext","list",a) ;
      	    }
      	```
      
      
    展开全文
  • 使用Aspect切面实现系统日志并存入数据库1.pom.xml中:加入Maven依赖&lt;dependency&gt; &lt;groupId&gt;org.springframework&lt;/groupId&gt; &lt;artifactId&gt;spring-aspects&...

    使用Aspect切面实现系统日志并存入数据库

    1.pom.xml中:加入Maven依赖

    <dependency>
    	<groupId>org.springframework</groupId>
    	<artifactId>spring-aspects</artifactId>
    	<version>${spring.version}</version>
    /dependency>

    2.SpringMVC.xml中:开启切面注解

    <aop:aspectj-autoproxy proxy-target-class="true" />

    3.自定义注解用于切面切入点

    import java.lang.annotation.*;
    
    /**
     * 系统日志注解
     * 
     * @author wangxueqing
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface SysLog {
    
       String value() default "";
    }

    4.自定义切面在方法执行时自动执行

    import com.alibaba.fastjson.JSON;
    import com.sm.share3d.annotion.SysLog;
    import com.sm.share3d.bean.SysLogEntity;
    import com.sm.share3d.utils.HttpContextUtils;
    import com.sm.share3d.utils.IPUtils;
    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.entity.UrlEncodedFormEntity;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.message.BasicNameValuePair;
    import org.apache.http.util.EntityUtils;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.stereotype.Component;
    
    import javax.servlet.http.HttpServletRequest;
    import java.lang.reflect.Method;
    import java.net.URLEncoder;
    import java.text.SimpleDateFormat;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    
    /**
     * 系统日志,切面处理类
     * 
     * @author wangxueqing
     */
    @Component
    @Aspect
    public class SysLogAspect {
    
       //切入点,以方法的形式存在
       @Pointcut("@annotation(com.sm.share3d.annotion.SysLog)")
       public void sportPoint(){
          System.out.println(1111111);
       }
    
       @Before("sportPoint()")
       public void before(JoinPoint joinPoint){
          MethodSignature signature = (MethodSignature) joinPoint.getSignature();
          Method method = signature.getMethod();
    
          SysLogEntity logEntity = new SysLogEntity();
          SysLog syslog = method.getAnnotation(SysLog.class);
          if(syslog != null){
             //注解上的描述
             logEntity.setOperation(syslog.value());
          }
    
          //请求的方法名
          String className = joinPoint.getTarget().getClass().getName();
          String methodName = signature.getName();
          logEntity.setMethod(className + "." + methodName + "()");
    
          //请求的参数
          Object[] args = joinPoint.getArgs();
          if(args.length>0){
             /*String params = JSON.toJSONString(args[0]);
             logEntity.setParams(params);*/
          }
    
    
          //获取request
          HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
          //设置IP地址
          logEntity.setIp(IPUtils.getIpAddr(request));
    
          //用户名
    //    String username = ShiroUtils.getUserEntity().getUsername();
          logEntity.setUsername(username);
          logEntity.setCreateDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
          sysLogService.save(logEntity);
       }
    }
    
    

    5.在Controller层需要保存日志的方法上加上自定义的注解

    /**
    * 保存用户
    * @param user
    * @return
    */
    @SysLog("新增用户")
    @RequestMapping("/saveUser")
    public R saveUser(@RequestBody User user){
        try {
    	userService.save(user);
    	return R.ok();
        } catch (Exception e) {
    	e.printStackTrace();
            return R.error("新增失败");
        }		
    }


    展开全文
  • 一,AOP切面实现 首先在pom里依赖aop,版本号:2.1.0.RELEASE 这里用Aop主要实现日志及异常处理,首先我们在接口层(lyn-web)创建一个Aop的切面类,如下: 定义好切面,然后写前置通知,后置通知,环绕通知...

    一,AOP切面实现

    首先在pom里依赖aop,版本号:2.1.0.RELEASE

    这里用Aop主要实现日志及异常处理,首先我们在接口层(lyn-web)创建一个Aop的切面类,如下:

    定义好切面,然后写前置通知,后置通知,环绕通知。

    前置通知主要打印了请求接口、IP、接口请求方式等信息,环绕通知抓取了接口的响应时间和异常处理,后置通知打印了相应的参数。接下来我将使用Aop实现一些其他功能。

    二,防SQL注入实现

    先写一个非法字符检验工具类:

    然后在AOP里写一个参数检查方法:

    再在环绕通知里执行访问接口前操作执行检查方法

    测试,参数带sql注入关键词(Drop  user_info)发起请求。

    看打印的日志:

    那我们去掉去掉非法关键词再发起请求:

    再看看日志:

    添加成功的数据库数据:

    注:项目源码已共享到Github,如果需要请扫码关注以下公众号,并发送“Springboot”获取。

    展开全文
  • 攻防演习的艰难决定 问题与挑战分析 解决思路 实现方案 总结(Take Away)
  • 此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为...
  • AOP切面实现方法日志打印耗时计算

    千次阅读 2018-04-12 17:40:57
    很简单,通过AOP实现每个方法访问时候统一进行日志打印和耗时计算,相关配置:1、spring配置在spring配置xml文件中设置启用aop &lt;aop:aspectj-autoproxy proxy-target-class="true" /&gt;2、aop...
  • Spring Boot 使用AOP切面实现后台日志管理模块

    万次阅读 多人点赞 2018-06-12 12:06:43
    3.定义日志AOP切面类(日志新增及修改其它业务操作不做介绍): package com.isoftstone.api.common.log.aspect; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Date; ...
  • Java 利用AOP切面实现自定义注解示例

    千次阅读 2019-07-22 16:30:21
    * AOP为Aspect Oriented Programming的缩写,意为:面向切面编程 * AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构 * AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到...
  • Spring AOP切面实现:参数传递

    万次阅读 2016-07-10 22:24:37
    切面: @Pointcut(value="args(p)") public void argsTest(int p) { } @Before(value="argsTest(p)",argNames="p") public void afterTest(JoinPoint jp,int p) { Object[] o = jp.getArgs(); ...
  • Spring AOP切面实现:异常处理

    千次阅读 2016-07-12 19:57:25
    异常
  • 此时需要对数据库做水平切分,常见的做法是按照用户的账号进行hash,然后选择对应的数据库,以下是在springboot项目中利用AOP面向切面技术实现两个不同数据库之间的来回切换功能 一 配置数据源连接池 application....
  • 首先是SpringBoot的注解介绍 @Configuration ...这个根据字面意思就是启用切面自动代理 需要注意的是这个注解加了系统并不会报错: 1当项目启动时才会报找不到这个包的错误 org.aspectj aspectjweave
  • 做这个功能之前 先讲一下AOP的环绕通知,因为这个功能我之前也想用springMVC的拦截器实现AOP的环绕通知、切面的优先级以及重用切入点定义一、环绕通知  环绕通知是所有通知类型中功能最为强大的, 能够全面地控制...
  • 2. 编写切面SysLogAspect类 package com.zhong.spring_demo.aspect; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 156,107
精华内容 62,442
关键字:

切面实现