Spring Security开发安全的REST服务-学习笔记(3.7-3.10)

欢迎

本篇博文仅记录该学习过程。

3.7使用切片拦截REST服务

Spring的切面拦截方式(Filter,Interceptor,AspectJ)

测试url请求的controller方法

package com.lwj.securitydemo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/hello/{id}")
    public String hello(@PathVariable int id) {
        return "hello";
    }
}

1.Filter的方式

(1)在Springboot项目中通过@Component注解的方式添加一个过滤器来拦截URL请求。

package com.lwj.securitydemo.filter;


import javax.servlet.*;
import java.io.IOException;
import java.util.Date;
//将TimeFilter添加到Spring容器中
@Component
public class TimeFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("TimeFilter init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("TimeFilter doFilter");
        System.out.println("start do something..." + new Date());
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("something is done" + new Date());
    }

    @Override
    public void destroy() {
        System.out.println("TimeFilter destroy");
    }
}

(2)使用Springboot的config配置的方式
新建WebConfig类,并添加@Configuration注解,将该类配置为一个配置类。

package com.lwj.securitydemo.config;

import com.lwj.securitydemo.TimeFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class WebConfig {
	/**
	 * 配置过滤器
	 * @return
	 */
	@Bean
    public FilterRegistrationBean timeFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        //  new一個自定義的filter出來
        TimeFilter timeFilter = new TimeFilter();
        //  將自定義的filter放入到registrationBean
        registrationBean.setFilter(timeFilter);

        //  設置需要被攔截的親求類型
        List<String> filterUrls = new ArrayList<>();
        filterUrls.add("/*");
        registrationBean.setUrlPatterns(filterUrls);

        return registrationBean;
    }
}

2.Interceptor的方式

(1)创建TimeInterceptor类

package com.lwj.securitydemo.interceptor;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

@Component
public class TimeInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle");
        Map map = request.getParameterMap();
        System.out.println(handler.getClass().getName());

        System.out.println("param "+ map.toString());
        return true;
    }
	/**
	 * 该方法如果调用的方法抛出异常就不会再被调用了
	 */
	@Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle");
    }

	/**
	*	该方法最终都会执行
	*/
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }
}

PS:此处的handler中虽然不能获取到请求中的参数,但是通过request对象中的方法也可以获取到param参数!
(2)将自定义的Interceptor添加到配置中

@Configuration
public class WebConfig implements WebMvcConfigurer {

    /**
     * 注入自定义的TimeInterceptor
     */
    @Autowired
    private TimeInterceptor timeInterceptor;

    /**
     * 配置自定义的Interceptor
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(timeInterceptor);
    }

    /**
     * 配置过滤器
     * @return
     */
    @Bean
    public FilterRegistrationBean timeFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        //  new一個自定義的filter出來
        TimeFilter timeFilter = new TimeFilter();
        //  將自定義的filter放入到registrationBean
        registrationBean.setFilter(timeFilter);

        //  設置需要被攔截的親求類型
        List<String> filterUrls = new ArrayList<>();
        filterUrls.add("/*");
        registrationBean.setUrlPatterns(filterUrls);

        return registrationBean;
    }
}

AspectJ方式

Spring Aop简介
Aspect方式代码

package com.lwj.securitydemo.web.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TimeAspect {

    @Around("execution(* com.lwj.securitydemo.controller.UserController.*(..))")
    public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("time aspect 方法被调用!");
        long start = System.currentTimeMillis();

        //  获取切片方法的参数
        Object[] args = pjp.getArgs();
        for (Object arg : args) {
            System.out.println("args : " + arg);
        }

        //  执行切片的方法
        Object obj = pjp.proceed();

        System.out.println("time aspect 耗时: " + (System.currentTimeMillis() - start));
        System.out.println("time aspect 方法结束!");
        return obj;
    }

}

REST API 拦截

拦截层次逻辑

3.9 异步处理REST服务

使用Runable异步处理Rest服务

package com.lwj.securitydemo.web.async;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Callable;

@RestController
public class AsyncController {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @RequestMapping("/order")
    public Callable<String> order() {
        logger.info("主线程开始!");

        Callable<String> result = () -> {
            logger.info("副线程开始!");
            Thread.sleep(1000);
            logger.info("副线程结束!");
            return "success";
        };
        logger.info("主线程结束!");

        return result;
    }
}
param org.apache.catalina.util.ParameterMap@16e52a1
2019-03-20 11:47:36.206  INFO 15556 --- [nio-8080-exec-1] c.l.s.web.async.AsyncController          : 主线程开始!
2019-03-20 11:47:36.207  INFO 15556 --- [nio-8080-exec-1] c.l.s.web.async.AsyncController          : 主线程结束!
2019-03-20 11:47:36.215  INFO 15556 --- [         task-1] c.l.s.web.async.AsyncController          : 副线程开始!
2019-03-20 11:47:37.216  INFO 15556 --- [         task-1] c.l.s.web.async.AsyncController          : 副线程结束!

可以看到日志信息中,在主线程结束后副线程立马开始了

使用DeferredResult异步处理Rest服务

1.创建MockQueue

package com.lwj.securitydemo.web.async;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class MockQueue {
    private Logger logger = LoggerFactory.getLogger(getClass());

    private String placeOrder;

    private String completeOrder;

    public String getPlaceOrder() {
        return placeOrder;
    }

    public void setPlaceOrder(String placeOrder) throws Exception {
        new Thread(() -> {
            logger.info("接到下单请求:" + placeOrder);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            this.completeOrder = placeOrder;
            logger.info("下单请求处理完毕:" + placeOrder);
        }).start();

    }

    public String getCompleteOrder() {
        return completeOrder;
    }

    public void setCompleteOrder(String completeOrder) {
        this.completeOrder = completeOrder;
    }
}

2.创建DeferredResultHolder类

package com.lwj.securitydemo.web.async;

import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.HashMap;
import java.util.Map;

@Component
public class DeferredResultHolder {

    private Map<String, DeferredResult<String>> map = new HashMap<>();

    public Map<String, DeferredResult<String>> getMap() {
        return map;
    }

    public void setMap(Map<String, DeferredResult<String>> map) {
        this.map = map;
    }
}

3.创建QueueListener

package com.lwj.securitydemo.web.async;

import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

/**
 * ContextRefreshedEvent 為spring容器初始化完畢事件
 */

@Component
public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private MockQueue mockQueue;

    @Autowired
    private DeferredResultHolder deferredResultHolder;


    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        new Thread(()->{
            while (true) {
                if (StrUtil.isNotBlank(mockQueue.getCompleteOrder())) {
                    String orderNumber = mockQueue.getCompleteOrder();
                    logger.info("返回订单处理结果:" + orderNumber);
                    deferredResultHolder.getMap().get(orderNumber).setResult("place order success");

                    mockQueue.setCompleteOrder(null);
                } else {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

4.修改AsyncController中的方法

package com.lwj.securitydemo.web.async;

import cn.hutool.core.util.RandomUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.concurrent.Callable;

@RestController
public class AsyncController {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private MockQueue mockQueue;

    @Autowired
    private DeferredResultHolder deferredResultHolder;

    @RequestMapping("/order")
    public DeferredResult<String> order() throws Exception {
        logger.info("主线程开始!");

        String orderNumber = RandomUtil.randomNumbers(8);
        mockQueue.setPlaceOrder(orderNumber);

        DeferredResult<String> result = new DeferredResult<>();
        deferredResultHolder.getMap().put(orderNumber, result);

//        Callable<String> result = () -> {
//            logger.info("副线程开始!");
//            Thread.sleep(1000);
//            logger.info("副线程结束!");
//            return "success";
//        };
        logger.info("主线程结束!");

        return result;
    }
}

console日志

2019-03-20 14:21:12.700  INFO 6508 --- [nio-8080-exec-1] c.l.s.web.async.AsyncController          : 主线程开始!
2019-03-20 14:21:12.701  INFO 6508 --- [nio-8080-exec-1] c.l.s.web.async.AsyncController          : 主线程结束!
2019-03-20 14:21:12.701  INFO 6508 --- [      Thread-10] c.lwj.securitydemo.web.async.MockQueue   : 接到下单请求:89428880
2019-03-20 14:21:13.702  INFO 6508 --- [      Thread-10] c.lwj.securitydemo.web.async.MockQueue   : 下单请求处理完毕:89428880
2019-03-20 14:21:13.703  INFO 6508 --- [       Thread-7] c.l.s.web.async.QueueListener            : 返回订单处理结果:89428880

异步处理配置

异步处理配置

猜你喜欢

转载自blog.csdn.net/weixin_38657051/article/details/88660449