使用Spring MVC开发RESTful API(续)

使用多线程提高REST服务性能

异步处理REST服务,提高服务器吞吐量

使用Runnable异步处理Rest服务

AsyncController.java

@RestController
@GetMapping("/async")
public class AsyncController {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @RequestMapping("/order")
    public Callable<String> order() throws Exception {
        logger.info("主线程开始");
        Callable<String> result = new Callable<String>() {
            @Override
            public String call() throws Exception {
                logger.info("副线程开始");
                Thread.sleep(2000); // 模拟处理下单消耗的时间
                logger.info("副线程结束");
                return "success";
            }
        };
        logger.info("主线程结束");
        return result;
    }
}

使用DeferredResult异步处理Rest服务

应用1/线程1:接收下单请求,放到消息队列

应用1/线程2:监听器,监听消息队列是否有下单处理结果,返回HTTP响应

应用2:处理下单逻辑

AsyncController.java

@GetMapping("/order2")
public DeferredResult<String> order2() throws Exception {
    logger.info("主线程开始");
    // 主线程,相当于图中应用1/线程1,接收HTTP请求
    // 收到下单请求,生成一个随机订单号,放到消息队列里
    String orderNumber = RandomStringUtils.randomNumeric(8);
    mockQueue.setPlaceOrder(orderNumber);

    // 用于接收处理结果
    DeferredResult<String> result = new DeferredResult<>();
    deferredResultHolder.getMap().put(orderNumber, result);
    logger.info("主线程结束");
    return result;
}

MockQueue.java,模拟队列

@Component
public class MockQueue {
    private String placeOrder; // 下单消息
    private String completeOrder; // 订单完成订单完成

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

    public String getPlaceOrder() {
        return placeOrder;
    }

    public void setPlaceOrder(String placeOrder) {
        // 此线程是模拟应用2,处理下单逻辑
        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.java ,用于在线程1与线程2之间传递传递DeferredResult对象

@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;
    }
}

QueueListener.java,监听器

@Component
public class QueueListener implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired
    private MockQueue mockQueue;

    @Autowired
    private DeferredResultHolder deferredResultHolder;

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

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        // 相当于图中应用1/线程2,模拟监听器
        new Thread(() -> {
            while (true) {
                if (StringUtils.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) {
                    }
                }
            }
        }).start();
    }
}

启动应用并访问http://localhost:8080/async/order2

异步处理配置

用拦截器拦截异步处理的请求以有线程池的配置

// 用拦截器拦截异步处理的请求,有如下两个方法注册拦截器,分别对应异步处理的两种方式
// 区别是有超时时间
// configurer.registerCallableInterceptors()
// configurer.registerDeferredResultInterceptors()

// Runnable使用的简单的异步线程池来处理,线程不可重用

使用Swagger自动生成文档

引入Swagger

引入相关依赖,immoc-security-demo/pom.xml

<!-- 引入swagger -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
</dependency>

加注解,DemoApplication.java

@EnableSwagger2 //  启用Swagger2

重启应用,访问链接http://localhost:8080/swagger-ui.html

详细描述

方法的描述

@ApiOperation(value = "用户查询服务")

参数的描述

// 参数被封装到对象里
@ApiModelProperty("用户名")
// 参数直接写在方法里
@ApiParam("用户ID")

使用WireMock伪造REST服务

与前端开发并行工作,开发阶段,前端包括app和页面开发时都需要测试数据,这时WireMock就派上用场了。这与你再写个web应用提供测试数据有什么不同呢。因为WireMock不用重启,定义url和返回数据都很方便。

下载并启动

下载:http://wiremock.org/docs/running-standalone/

指定端口启动:

java -jar wiremock-standalone-2.18.0.jar --port 9999
# --port 9999 指定端口,默认端口8080, --port 0 随机端口

模拟请求和响应

引入依赖

<!--  引入WireMock-->
<dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
</dependency>

编写代码,MockServer.java

public class MockServer {
    public static void main(String[] args) throws IOException {
        configureFor("192.168.5.210", 9999);
        // configureFor(9999);
        removeAllMappings();

        mock("/order/1", "01.txt");
        mock("/order/2", "02.txt");
    }

    private static void mock(String url, String fileName) throws IOException {
        ClassPathResource resource =
            new ClassPathResource("mock/response/" + fileName);
        String content =
            StringUtils.join(FileUtils.readLines(resource.getFile(), "UTF-8"), "\n");
        stubFor(get(urlPathEqualTo(url))
                .willReturn(aResponse().withBody(content).withStatus(200)));
    }
}

原文地址:https://www.cnblogs.com/okokabcd/p/9589025.html

时间: 2024-10-08 20:10:46

使用Spring MVC开发RESTful API(续)的相关文章

Spring mvc之Restful API

这是一个路径,http://127.0.0.1:8080/OperationAPI/v0.1/pins/3是API的具体网址.在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应.一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数.http://127.0.0.1:8080表示的本地的域名,OperationAPI表示的是项目名称,v0.1表示的ap

开发restful api总结的几点小经验

与其说是开发,不如说是打补丁! 是个jesery+spring的restful service,加了一个权限校验部分,做了一些调整. 本来其实很简单的一个事,后来发现,这个代码太霸道.本来传个参数是action_id 这个东西,结果参数名字有如下:action_id,actionID,id 我只能说傻傻分不清楚到底你传的什么, 因为还有其他id,参数名字参考刚才的. 代码中的也是混乱,虽然我知道有很多先人在修改了,但是也不至于这样吧. 吐槽完毕. 1.N次开发restful api主意版本迭代,

flask开发restful api

在此之前,向大家说明的是,我们整个框架用的是flask + sqlalchemy + redis.如果没有开发过web,还是先去学习一下,这边只是介绍如果从开发web转换到开发移动端.如果flask还不是很熟悉,我建议先到这个网站简单学习一下,非常非常简单.http://dormousehole.readthedocs.org/en/latest/ 一直想写一些特别的东西,能让大家学习讨论的东西.但目前网上的很多博客,老么就按照官方文档照本宣读,要么直接搬代码,什么都不说明.我写这个系列的博客,

Maven+Hibernate+Spring+Spring MVC开发新闻发布系统

使用Maven+Hibernate+Spring+Spring MVC开发新闻发布系统 课程学习地址:http://www.xuetuwuyou.com/course/163 课程出自学途无忧网:http://www.xuetuwuyou.com 课程介绍 一.课程用到的软件: 1.jdk 1.8 2.eclipse neon 3.tomcat 8 4.jetty 5.MySQL  6.navicat 9+ 二.课程涉及到的技术点 1.Maven基础 2.Maven高级 3.Hibernate

用Spring MVC开发简单的Web应用

这个例子是来自于Gary Mak等人写的Spring攻略(第二版)第八章Spring @MVC中的一个例子,在此以学习为目的进行记录. 问题:想用Spring MVC开发一个简单的Web应用, 学习这个框架的基本概念和配置. 解决方案: Spring MVC的核心组件是一个控制器(大多数框架都是控制器比较重要吧). 在最简单的Spring MVC应用中,控制器是需要在web.xml文件中配置的唯一Servlet. Spring MVC的控制器通常称作请求分发Servlet(Dispatcher

应用Spring MVC发布restful服务是怎样的一种体验

摘要:“约定优于配置”这是一个相当棒的经验,SOAP服务性能差.基于配置.紧耦合,restful服务性能好.基于约定.松耦合,现在我就把使用Spring MVC发布restful服务的过程同大家分享.代码之优雅.过程之简单.编码之愉快,不是发布SOAP服务所能匹敌的. 关键字:java, rest, webservice, spring mvc 前提:IntelliJ IDEA (13.1.5 版本), apache maven (3.2.3 版本), Tomcat(7.0.56版本), Spr

spring mvc开发入门实例demo源代码下载,很适合新手入门学习用。

原文:spring mvc开发入门实例demo源代码下载,很适合新手入门学习用. 源代码下载:http://www.zuidaima.com/share/1550463469046784.htm Eclipse + Maven + Spring MVC - Simple Example 源代码框架截图:

使用Spring boot开发RestFul 风格项目PUT/DELETE方法不起作用

在使用Spring boot 开发restful 风格的项目,put.delete方法不起作用,解决办法. 实体类Student @Data public class Student { private String id; private String name; private int age; private String sex; @Override public String toString() { return ToStringBuilder.reflectionToString(

搭建基于spring MVC框架 + RESTful架构风格技术总结

实战篇: 在SpringMVC框架中搭建RESTful架构风格来完成客户端与服务器端的低耦合度.可扩展性.高并发与大数据流量的访问. 用RESTful架构的创建步骤: 1.创建一个全新的Web工程 2.导包,导入所需要的所有第三方jar包.(springMVC+Hibernate的基本包是必须的) 3.作配置,针对不同的项目需求和不同的搭建设计,开发人员可以按照自己的编码风格来设计符合项目开发具体 应该用多少篇配置文件.但是这几篇配置文件是必不可少的: 3-1.web.xml配置文件:最基本的配