美文网首页
Spring Security 安全之路进阶(二)

Spring Security 安全之路进阶(二)

作者: Seapp | 来源:发表于2020-08-06 13:16 被阅读0次

    第一章 使用REST方式处理文件服务

    • 文件上传
    • 文件下载
    package com.seapp.web.controller;
    
    import com.seapp.dto.FileInfo;
    import com.sun.org.apache.xml.internal.serializer.OutputPropertiesFactory;
    import org.apache.commons.io.IOUtils;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.*;
    import java.util.Date;
    
    /**文件上传与下载controller实现
     * @author seapp
     * @date 2020/8/5 22:41
     */
    @RestController
    @RequestMapping("/file")
    public class FileController {
    
        private String folder = "D:\\javaEE\\security\\security-demo\\src\\main\\java\\com\\seapp\\web\\controller\\";
    
        @PostMapping
        public FileInfo upload(MultipartFile file) throws IOException {
    
            String name = file.getName();
            System.out.println("name = " + name);
            String originalFilename = file.getOriginalFilename();
            System.out.println("originalFilename = " + originalFilename);
            long size = file.getSize();
            System.out.println("size = " + size);
    
    
            File localFile = new File(folder, new Date().getTime() + ".txt");
            file.transferTo(localFile);
    
            return new FileInfo(localFile.getAbsolutePath());
    
        }
    
        @GetMapping("/{id}")
        public void download(@PathVariable("id") String id,
                             HttpServletRequest request, HttpServletResponse response) throws IOException {
    
            try (
                    InputStream inputStream = new FileInputStream(folder + id + ".txt");
                    OutputStream outputStream = response.getOutputStream();
            ) {
                response.setContentType("application/x-download");
                response.addHeader("Content-Disposition","attachment;filename=test.txt");
                IOUtils.copy(inputStream,outputStream);
                outputStream.flush();
            }
        }
    
    }
    
    
    package com.seapp.web;
    
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.http.MediaType;
    import org.springframework.mock.web.MockMultipartFile;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
    import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
    import org.springframework.test.web.servlet.setup.MockMvcBuilders;
    import org.springframework.web.context.WebApplicationContext;
    
    import java.io.UnsupportedEncodingException;
    import java.time.LocalDateTime;
    import java.time.ZoneId;
    import java.util.Date;
    
    /**
     * 测试用例
     * @author seapp
     * @date 2020/8/4 17:33
     */
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class UpdateFileControllerTest {
    
        @Autowired
        private WebApplicationContext wac;
    
        private MockMvc mockMvc;
    
        @Before
        public void before(){
            mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
        }
        
        @Test
        public void whenUploadSuccess() throws Exception {
            String result = mockMvc.perform(MockMvcRequestBuilders.fileUpload("/file")
                    .file(new MockMultipartFile("file", "text.txt"
                            , "multipart/form-data"
                            , "hello upload".getBytes("UTF-8"))))
                    .andExpect(MockMvcResultMatchers.status().isOk())
                    .andReturn().getResponse().getContentAsString();
            System.out.println("result = " + result);
        }
        
    }
    
    

    第二章 Spring MVC 高级特性

    1. 异步处理REST服务

    异步处理提高服务性能
    • 使用Runnable异步处理Rest服务
      ①代码实现
    package com.seapp.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;
    
    /**
     * 异步处理控制器
     * @author seapp
     * @date 2020/8/5 23:22
     */
    @RestController
    public class AsyncController {
    
        private Logger logger = LoggerFactory.getLogger(AsyncController.class);
    
        @RequestMapping("/order")
        public Callable<String> order() throws InterruptedException {
    
            logger.info("主线程开始");
    
            Callable<String> result = new Callable<String>() {
                @Override
                public String call() throws Exception {
                    logger.info("副线程开始");
                    Thread.sleep(1000);
                    logger.info("副线程返回");
                    return "success";
                }
            };
            
            logger.info("主线程结束");
            return result;
        }
    
    }
    
    

    ②实现结果:

    主线程无需等待,提高了服务器的吞吐量
    • 使用DeferredResult异步处理Rest服务


    实例:
    订单队列中定义两个变量:
    placeOrder:有值时或对该属性赋值时,表示有新订单产生。
    completeOrder:订单处理完成后,将订单id赋予该值。
    图示中线程2实现对completeOrder属性监听,当该属性有值时,代表订单已处理完成,通过DeferredResult将处理结果返回。


    ①DeferredResult异步请求Controller层实现

    package com.seapp.async;
    
    import org.apache.commons.lang.RandomStringUtils;
    import org.mockito.Mock;
    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;
    
    /**
     * 异步处理控制器
     * @author seapp
     * @date 2020/8/5 23:22
     */
    @RestController
    public class AsyncController {
    
        @Autowired
        private MockQueue mockQueue;
    
        @Autowired
        private DeferredResultHolder deferredResultHolder;
    
        private Logger logger = LoggerFactory.getLogger(AsyncController.class);
    
        @RequestMapping("/order")
        public DeferredResult<String> order() throws InterruptedException {
    
            logger.info("主线程开始");
    
            String orderNumber = RandomStringUtils.randomNumeric(8);
            mockQueue.setPlaceOrder(orderNumber);
    
            DeferredResult<String> result = new DeferredResult<>();
            deferredResultHolder.getMap().put(orderNumber,result);
    
            logger.info("主线程结束");
            return result;
        }
    
    }
    
    

    ② MockQueue 实现对消息队列以及应用2的模拟处理

    package com.seapp.async;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    /**
     * 模拟队列
     *
     * @author seapp
     * @date 2020/8/5 23:47
     */
    @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 InterruptedException {
    
            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;
        }
    }
    

    ③ DeferredResultHolder类的实现

    package com.seapp.async;
    
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.async.DeferredResult;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author seapp
     * @date 2020/8/5 23:55
     */
    @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;
        }
    }
    
    

    ④ 线程2的模拟,对响应结果的处理

    package com.seapp.async;
    
    import org.apache.commons.lang.StringUtils;
    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;
    
    /**
     * @author seapp
     * @date 2020/8/6 0:01
     */
    @Component
    public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {
    
        @Autowired
        private MockQueue mockQueue;
    
        @Autowired
        private DeferredResultHolder deferredResultHolder;
    
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        /**
         * 系统启动初始化完成后,需要实现的功能
         *
         * @param contextRefreshedEvent
         */
        @Override
        public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
    
            //死循环处理逻辑,需在子线程中处理
            new Thread(() -> {
                while (true) {
                    if (StringUtils.isNotBlank(mockQueue.getCompleteOrder())) {
    
                        String completeOrder = mockQueue.getCompleteOrder();
                        logger.info("返回订单处理结果:" + completeOrder);
                        deferredResultHolder.getMap().get(completeOrder).setResult("place order success");
                        mockQueue.setCompleteOrder(null);
    
                    } else {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
    
    
        }
    }
    

    ⑥处理结果


    • 异步处理配置
    @Configuration
    public class WebConfig extends WebMvcConfigurerAdapter {
     /**
         * 异步情况下,拦截器的配置
         * @param configurer
         */
        @Override
        public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    
            configurer.registerCallableInterceptors();
            configurer.registerDeferredResultInterceptors();
            configurer.setDefaultTimeout(1000*6);//设置超时时间
            configurer.setTaskExecutor()
        }
    }
    

    第三章、 REST服务开发常用工具

    1.使用swagger自动生成html文档

    • maven依赖引入
      <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-boot-starter</artifactId>
                <version>3.0.0</version>
            </dependency>
    
    • 配置启动swagger
    package com.seapp.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    import springfox.documentation.oas.annotations.EnableOpenApi;
    import springfox.documentation.spi.DocumentationType;
    import springfox.documentation.spring.web.plugins.Docket;
    
    /**
     * @author seapp
     * @date 2020/8/6 10:38
     */
    @Configuration
    @EnableOpenApi
    public class Swagger3Configuration implements WebMvcConfigurer {
    
        @Bean
        public Docket createRestApi(){
            return new Docket(DocumentationType.OAS_30).pathMapping("/")
                    .enable(true);//定义是否开启swagger注解,true为开启,false为关闭。
        }
    
    }
    
    • swagger访问地址:
    http://localhost:8090/swagger-ui/index.html
    
    • swagger常用注解
    @Api(tags = "用户的增删改查接口处理")//标明该Controller类
    @ApiOperation(value = "用户查询服务")//标明该方法
    @ApiParam("用户id") @PathVariable("id") String id //标明请求参数
    //标明实体类中属性的定义    
    @ApiModelProperty("用户密码")
    private String password;
    
    

    2.使用WireMock快速伪造RESTful服务

    官网地址:
    http://wiremock.org/

    • WireMock的安装与运行:独立安装,以jar包形式运行

    指定端口为8062
    • pom文件中maven依赖的引入
     <!-- https://mvnrepository.com/artifact/com.github.tomakehurst/wiremock -->
            <dependency>
                <groupId>com.github.tomakehurst</groupId>
                <artifactId>wiremock</artifactId>
                <version>2.27.1</version>
            </dependency>
    
    • 通过Java代码实现对本地WireMock服务中策略的配置
    package com.seapp.wiremock;
    
    import com.github.tomakehurst.wiremock.client.WireMock;
    import nonapi.io.github.classgraph.utils.URLPathEncoder;
    import org.apache.commons.io.FileUtils;
    import org.apache.commons.lang.StringUtils;
    import org.apache.http.impl.conn.Wire;
    import org.springframework.core.io.ClassPathResource;
    
    import java.io.IOException;
    
    /**
     * @author seapp
     * @date 2020/8/6 12:45
     */
    public class WireMockService {
    
        public static void main(String[] args) throws IOException {
            WireMock.configureFor(8062);
            WireMock.removeAllMappings();
            //可指定不同的接口访问,以及对应的json返回数据文件。
            mock("/order/1","01");
    
    
        }
    
        /**
         * 对wiremock数据的封装
         * @param url
         * @param fileName
         * @throws IOException
         */
        private static void mock(String url, String fileName) throws IOException {
            //获取本地资源,转换为字符串
            ClassPathResource classPathResource = new ClassPathResource("mock/response/"+fileName+".txt");
            String content = StringUtils
                    .join(FileUtils.readLines(classPathResource.getFile(),"UTF-8")
                            .toArray(),"\n") ;
            WireMock.stubFor(WireMock.get(WireMock.urlPathEqualTo(url))
                    .willReturn(WireMock.aResponse()
                            .withBody(content).withStatus(200)));
        }
    
    }
    
    

    相关文章

      网友评论

          本文标题:Spring Security 安全之路进阶(二)

          本文链接:https://www.haomeiwen.com/subject/vusorktx.html