本篇是对springboot 使用webflux响应式开发教程(一)的进一步学习。
分三个部分:

数据库操作
webservice
websocket
创建项目,artifactId = trading-service,groupId=io.spring.workshop。选择Reactive Web , Devtools, Thymeleaf , Reactive Mongo。
WEB容器
spring-boot-starter-webflux 附带了 spring-boot-starter-reactor-netty,所以默认使用Reactor Netty作为web server。
如果要用Tomcat,添加pom即可

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-tomcat</artifactId>
  4. </dependency>
  1. 同样支持UndertowJetty

响应式数据库操作

这个示例使用MongoDB。作为reactive模式,数据库的驱动与传统模式区分开。截至目前还没有mysql的reactive驱动,据悉正在研发。本例中使用内存版的mongodb,需要添加依赖

  1. <dependency>
  2. <groupId>de.flapdoodle.embed</groupId>
  3. <artifactId>de.flapdoodle.embed.mongo</artifactId>
  4. </dependency>
  1. 在初次运行时会自动下载mongodb模块,但是墙国是直连不到mongodb的官网,所以在需要添加代理。在这推荐使用JVM参数的方式,-DproxySet=true -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=。需要注意的是httphttps协议是区分开来配置的,如果需要http的代理就需要把Dhttps改为Dhttp
  2. 数据库的存储实体 TradingUser
  1. @Document
  2. @Data
  3. public class TradingUser {
  4.  
  5. @Id
  6. private String id;
  7.  
  8. private String userName;
  9.  
  10. private String fullName;
  11.  
  12. public TradingUser() {
  13. }
  14.  
  15. public TradingUser(String id, String userName, String fullName) {
  16. this.id = id;
  17. this.userName = userName;
  18. this.fullName = fullName;
  19. }
  20.  
  21. public TradingUser(String userName, String fullName) {
  22. this.userName = userName;
  23. this.fullName = fullName;
  24. }
  25.  
  26. @Override
  27. public boolean equals(Object o) {
  28. if (this == o) return true;
  29. if (o == null || getClass() != o.getClass()) return false;
  30.  
  31. TradingUser that = (TradingUser) o;
  32.  
  33. if (!id.equals(that.id)) return false;
  34. return userName.equals(that.userName);
  35. }
  36.  
  37. @Override
  38. public int hashCode() {
  39. int result = id.hashCode();
  40. result = * result + userName.hashCode();
  41. return result;
  42. }
  43. }

创建TradingUserRepository继承ReactiveMongoRepository。添加findByUserName方法返回一个实体。
在项目启动的时候我们要初始化一些数据,为此创建UsersCommandLineRunner并继承CommandLineRunner并重写run方法,在该方法里初始化数据,并插入到数据库中。

  1. @Component
  2. public class UsersCommandLineRunner implements CommandLineRunner {
  3.  
  4. private final TradingUserRepository repository;
  5.  
  6. public UsersCommandLineRunner(TradingUserRepository repository) {
  7. this.repository = repository;
  8. }
  9.  
  10. @Override
  11. public void run(String... strings) throws Exception {
  12. List<TradingUser> users = Arrays.asList(
  13. new TradingUser("sdeleuze", "Sebastien Deleuze"),
  14. new TradingUser("snicoll", "Stephane Nicoll"),
  15. new TradingUser("rstoyanchev", "Rossen Stoyanchev"),
  16. new TradingUser("poutsma", "Arjen Poutsma"),
  17. new TradingUser("smaldini", "Stephane Maldini"),
  18. new TradingUser("simonbasle", "Simon Basle"),
  19. new TradingUser("violetagg", "Violeta Georgieva"),
  20. new TradingUser("bclozel", "Brian Clozel")
  21. );
  22. this.repository.insert(users).blockLast(Duration.ofSeconds());
  23. }
  24. }
  1. 由于该方法是void类型,实现是阻塞的,因此在 repository 插入数据返回Flux的时候需要调用 blockLast(Duration)
  2. 。也可以使用 then().block(Duration) Flux 转化为 Mono<Void> 等待执行结束。

创建 webservice, @RestController标注 的 UserController,添加两个控制器方法
1、get请求,”/users”,返回所有TradingUser,content-type = “application/json”
2、get请求,”/users/{username}”,返回单个TradingUser,content-type = “application/json”

  1. @RestController
  2. public class UserController {
  3.  
  4. private final TradingUserRepository tradingUserRepository;
  5.  
  6. public UserController(TradingUserRepository tradingUserRepository) {
  7. this.tradingUserRepository = tradingUserRepository;
  8. }
  9. @GetMapping(path = "/users", produces = MediaType.APPLICATION_JSON_VALUE)
  10. public Flux<TradingUser> listUsers() {
  11. return this.tradingUserRepository.findAll();
  12. }
  13.  
  14. @GetMapping(path = "/users/{username}", produces = MediaType.APPLICATION_JSON_VALUE)
  15. public Mono<TradingUser> showUsers(@PathVariable String username) {
  16. return this.tradingUserRepository.findByUserName(username);
  17. }
  18. }

编写测试

  1. @RunWith(SpringRunner.class)
  2. @WebFluxTest(UserController.class)
  3. public class UserControllerTests {
  4.  
  5. @Autowired
  6. private WebTestClient webTestClient;
  7.  
  8. @MockBean
  9. private TradingUserRepository repository;
  10.  
  11. @Test
  12. public void listUsers() {
  13. TradingUser juergen = new TradingUser("", "jhoeller", "Juergen Hoeller");
  14. TradingUser andy = new TradingUser("", "wilkinsona", "Andy Wilkinson");
  15.  
  16. BDDMockito.given(this.repository.findAll())
  17. .willReturn(Flux.just(juergen, andy));
  18.  
  19. this.webTestClient.get().uri("/users").accept(MediaType.APPLICATION_JSON)
  20. .exchange()
  21. .expectBodyList(TradingUser.class)
  22. .hasSize()
  23. .contains(juergen, andy);
  24.  
  25. }
  26.  
  27. @Test
  28. public void showUser() {
  29. TradingUser juergen = new TradingUser("", "jhoeller", "Juergen Hoeller");
  30.  
  31. BDDMockito.given(this.repository.findByUserName("jhoeller"))
  32. .willReturn(Mono.just(juergen));
  33.  
  34. this.webTestClient.get().uri("/users/jhoeller").accept(MediaType.APPLICATION_JSON)
  35. .exchange()
  36. .expectBody(TradingUser.class)
  37. .isEqualTo(juergen);
  38. }
  39.  
  40. }

用Thymeleaf渲染页面 
pom添加前端依赖

  1. <dependency>
  2. <groupId>org.webjars</groupId>
  3. <artifactId>bootstrap</artifactId>
  4. <version>3.3.</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.webjars</groupId>
  8. <artifactId>highcharts</artifactId>
  9. <version>5.0.</version>
  10. </dependency>

创建HomeController

  1. @Controller
  2. public class HomeController {
  3.  
  4. private final TradingUserRepository tradingUserRepository;
  5.  
  6. public HomeController(TradingUserRepository tradingUserRepository) {
  7. this.tradingUserRepository = tradingUserRepository;
  8. }
  9.  
  10. @GetMapping("/")
  11. public String home(Model model) {
  12. model.addAttribute("users", this.tradingUserRepository.findAll());
  13. return "index";
  14. }
  15. }

创建首页

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="utf-8"/>
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
  6. <meta name="viewport" content="width=device-width, initial-scale=1"/>
  7. <meta name="description" content="Spring WebFlux Workshop"/>
  8. <meta name="author" content="Violeta Georgieva and Brian Clozel"/>
  9. <title>Spring Trading application</title>
  10. <link rel="stylesheet" href="/webjars/bootstrap/3.3.7/css/bootstrap-theme.min.css"/>
  11. <link rel="stylesheet" href="/webjars/bootstrap/3.3.7/css/bootstrap.min.css"/>
  12. </head>
  13. <body>
  14. <nav class="navbar navbar-default">
  15. <div class="container-fluid">
  16. <div class="navbar-header">
  17. <a class="navbar-brand" href="/">Spring Trading application</a>
  18. </div>
  19. <div id="navbar" class="navbar-collapse collapse">
  20. <ul class="nav navbar-nav">
  21. <li class="active"><a href="/">Home</a></li>
  22. <li><a href="/quotes">Quotes</a></li>
  23. <li><a href="/websocket">Websocket</a></li>
  24. </ul>
  25. </div>
  26. </div>
  27. </nav>
  28. <div class="container wrapper">
  29. <h2>Trading users</h2>
  30. <table class="table table-striped">
  31. <thead>
  32. <tr>
  33. <th>#</th>
  34. <th>User name</th>
  35. <th>Full name</th>
  36. </tr>
  37. </thead>
  38. <tbody>
  39. <tr th:each="user: ${users}">
  40. <th scope="row" th:text="${user.id}"></th>
  41. <td th:text="${user.userName}">janedoe</td>
  42. <td th:text="${user.fullName}">Jane Doe</td>
  43. </tr>
  44. </tbody>
  45. </table>
  46. </div>
  47. <script type="text/javascript" src="/webjars/jquery/1.11.1/jquery.min.js"></script>
  48. <script type="text/javascript" src="/webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  49. </body>
  50. </html>
  1. Spring WebFlux在渲染视图之前自动解析Publisher实例,因此不需包含阻塞代码

使用WebClient 将 stream JSON 输送到浏览器

现在要用到springboot 使用webflux响应式开发教程(一)的示例,远程调用该服务。然后创建视图

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="utf-8"/>
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
  6. <meta name="viewport" content="width=device-width, initial-scale=1"/>
  7. <meta name="description" content="Spring WebFlux Workshop"/>
  8. <meta name="author" content="Violeta Georgieva and Brian Clozel"/>
  9. <title>Spring Trading application</title>
  10. <link rel="stylesheet" href="/webjars/bootstrap/3.3.7/css/bootstrap-theme.min.css"/>
  11. <link rel="stylesheet" href="/webjars/bootstrap/3.3.7/css/bootstrap.min.css"/>
  12. <link rel="stylesheet" href="/webjars/highcharts/5.0.8/css/highcharts.css"/>
  13. </head>
  14. <body>
  15. <nav class="navbar navbar-default">
  16. <div class="container-fluid">
  17. <div class="navbar-header">
  18. <a class="navbar-brand" href="/">Spring Trading application</a>
  19. </div>
  20. <div id="navbar" class="navbar-collapse collapse">
  21. <ul class="nav navbar-nav">
  22. <li><a href="/">Home</a></li>
  23. <li class="active"><a href="/quotes">Quotes</a></li>
  24. <li><a href="/websocket">Websocket</a></li>
  25. </ul>
  26. </div>
  27. </div>
  28. </nav>
  29. <div class="container wrapper">
  30. <div id="chart" style="height: 400px; min-width: 310px"></div>
  31. </div>
  32. <script type="text/javascript" src="/webjars/jquery/1.11.1/jquery.min.js"></script>
  33. <script type="text/javascript" src="/webjars/highcharts/5.0.8/highcharts.js"></script>
  34. <script type="text/javascript" src="/webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  35. <script type="text/javascript">
  36.  
  37. // Setting up the chart
  38. var chart = new Highcharts.chart('chart', {
  39. title: {
  40. text: 'My Stock Portfolio'
  41. },
  42. yAxis: {
  43. title: {
  44. text: 'Stock Price'
  45. }
  46. },
  47. legend: {
  48. layout: 'vertical',
  49. align: 'right',
  50. verticalAlign: 'middle'
  51. },
  52. xAxis: {
  53. type: 'datetime',
  54. },
  55. series: [{
  56. name: 'CTXS',
  57. data: []
  58. }, {
  59. name: 'MSFT',
  60. data: []
  61. }, {
  62. name: 'ORCL',
  63. data: []
  64. }, {
  65. name: 'RHT',
  66. data: []
  67. }, {
  68. name: 'VMW',
  69. data: []
  70. }, {
  71. name: 'DELL',
  72. data: []
  73. }]
  74. });
  75.  
  76. // This function adds the given data point to the chart
  77. var appendStockData = function (quote) {
  78. chart.series
  79. .filter(function (serie) {
  80. return serie.name == quote.ticker
  81. })
  82. .forEach(function (serie) {
  83. var shift = serie.data.length > ;
  84. serie.addPoint([new Date(quote.instant), quote.price], true, shift);
  85. });
  86. };
  87.  
  88. // The browser connects to the server and receives quotes using ServerSentEvents
  89. // those quotes are appended to the chart as they're received
  90. var stockEventSource = new EventSource("/quotes/feed");
  91. stockEventSource.onmessage = function (e) {
  92. appendStockData(JSON.parse(e.data));
  93. };
  94. </script>
  95. </body>
  96. </html>
  1. 页面会通过Server Sent EventSSE 向服务器请求Quotes

创建控制器QuotesController并添加两个方法如下

  1. @Controller
  2. public class QuotesController {
  3.  
  4. @GetMapping("/quotes")
  5. public String quotes() {
  6. return "quotes";
  7. }
  8.  
  9. @GetMapping(path = "/quotes/feed", produces = TEXT_EVENT_STREAM_VALUE)
  10. @ResponseBody
  11. public Flux<Quote> quotesStream() {
  12. return WebClient.create("http://localhost:8081")
  13. .get()
  14. .uri("/quotes")
  15. .accept(APPLICATION_STREAM_JSON)
  16. .retrieve()
  17. .bodyToFlux(Quote.class)
  18. .share()
  19. .log("io.spring.workshop.tradingservice");
  20. }
  21. }
  1. quotesStream方法返回的content-type为”text/event-stream”,并将Flux<Quote>作为响应主体,数据已由stock-quotes提供,在这使用WebClient来请求并检索数据。
  2. 同时应该避免为每个浏览器的请求都去向数据服务提供方发送请求,可以使用Flux.share()

接下来进入页面查看效果

创建WebSocket Handler
WebFlux 支持函数响应式WebSocket 客户端和服务端。
服务端主要分两部分:WebSocketHandlerAdapter 负责处理请求,然后委托给WebSocketService和WebSocketHandler返回响应完成会话。
spring mvc 的 reactive websocket 官方文档参考 这里.

先创建EchoWebSocketHandler 实现 WebSocketHandler接口

  1. public class EchoWebSocketHandler implements WebSocketHandler {
  2.  
  3. @Override
  4. public Mono<Void> handle(WebSocketSession session) {
  5. return session.send(session.receive()
  6. .doOnNext(WebSocketMessage::retain)
  7. .delayElements(Duration.ofSeconds()).log());
  8. }
  9. }

实现handle方法,接收传入的消息然后在延迟一秒后输出。 
为了将请求映射到Handler,需要创建WebSocketRouter

  1. @Configuration
  2. public class WebSocketRouter {
  3.  
  4. @Bean
  5. public HandlerMapping handlerMapping() {
  6.  
  7. Map<String, WebSocketHandler> map = new HashMap<>();
  8. map.put("/websocket/echo", new EchoWebSocketHandler());
  9.  
  10. SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
  11. mapping.setOrder();
  12. mapping.setUrlMap(map);
  13. return mapping;
  14. }
  15.  
  16. @Bean
  17. public WebSocketHandlerAdapter handlerAdapter() {
  18. return new WebSocketHandlerAdapter();
  19. }
  20. }

然后创建WebSocketController

  1. @Controller
  2. public class WebSocketController {
  3.  
  4. @GetMapping("/websocket")
  5. public String websocket() {
  6. return "websocket";
  7. }
  8. }

返回视图,在页面上查看效果

  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <meta charset="utf-8"/>
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
  6. <meta name="viewport" content="width=device-width, initial-scale=1"/>
  7. <meta name="description" content="Spring WebFlux Workshop"/>
  8. <meta name="author" content="Violeta Georgieva and Brian Clozel"/>
  9. <title>Spring Trading application</title>
  10. <link rel="stylesheet" href="/webjars/bootstrap/3.3.7/css/bootstrap-theme.min.css"/>
  11. <link rel="stylesheet" href="/webjars/bootstrap/3.3.7/css/bootstrap.min.css"/>
  12. </head>
  13. <body>
  14. <nav class="navbar navbar-default">
  15. <div class="container-fluid">
  16. <div class="navbar-header">
  17. <a class="navbar-brand" href="/">Spring Trading application</a>
  18. </div>
  19. <div id="navbar" class="navbar-collapse collapse">
  20. <ul class="nav navbar-nav">
  21. <li><a href="/">Home</a></li>
  22. <li><a href="/quotes">Quotes</a></li>
  23. <li class="active"><a href="/websocket">Websocket</a></li>
  24. </ul>
  25. </div>
  26. </div>
  27. </nav>
  28. <div class="container wrapper">
  29. <h2>Websocket Echo</h2>
  30. <form class="form-inline">
  31. <div class="form-group">
  32. <input class="form-control" type="text" id="input" value="type something">
  33. <input class="btn btn-default" type="submit" id="button" value="Send"/>
  34. </div>
  35. </form>
  36. <div id="output"></div>
  37. </div>
  38. <script type="text/javascript" src="/webjars/jquery/1.11.1/jquery.min.js"></script>
  39. <script type="text/javascript" src="/webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  40. <script type="text/javascript">
  41. $(document).ready(function () {
  42. if (!("WebSocket" in window)) WebSocket = MozWebSocket;
  43. var socket = new WebSocket("ws://localhost:8080/websocket/echo");
  44.  
  45. socket.onopen = function (event) {
  46. var newMessage = document.createElement('p');
  47. newMessage.textContent = "-- CONNECTED";
  48. document.getElementById('output').appendChild(newMessage);
  49.  
  50. socket.onmessage = function (e) {
  51. var newMessage = document.createElement('p');
  52. newMessage.textContent = "<< SERVER: " + e.data;
  53. document.getElementById('output').appendChild(newMessage);
  54. }
  55.  
  56. $("#button").click(function (e) {
  57. e.preventDefault();
  58. var message = $("#input").val();
  59. socket.send(message);
  60. var newMessage = document.createElement('p');
  61. newMessage.textContent = ">> CLIENT: " + message;
  62. document.getElementById('output').appendChild(newMessage);
  63. });
  64. }
  65. });
  66. </script>
  67. </body>
  68. </html>

也可以使用WebSocketClient写测试

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
  3. public class EchoWebSocketHandlerTests {
  4.  
  5. @LocalServerPort
  6. private String port;
  7.  
  8. @Test
  9. public void echo() throws Exception {
  10. int count = ;
  11. Flux<String> input = Flux.range(, count).map(index -> "msg-" + index);
  12. ReplayProcessor<Object> output = ReplayProcessor.create(count);
  13.  
  14. WebSocketClient client = new StandardWebSocketClient();
  15. client.execute(getUrl("/websocket/echo"),
  16. session -> session
  17. .send(input.map(session::textMessage))
  18. .thenMany(session.receive().take(count).map(WebSocketMessage::getPayloadAsText))
  19. .subscribeWith(output)
  20. .then())
  21. .block(Duration.ofMillis());
  22.  
  23. assertEquals(input.collectList().block(Duration.ofMillis()), output.collectList().block(Duration.ofMillis()));
  24. }
  25.  
  26. protected URI getUrl(String path) throws URISyntaxException {
  27. return new URI("ws://localhost:" + this.port + path);
  28. }
  29. }

github源码地址

springboot 使用webflux响应式开发教程(二)的更多相关文章

  1. springboot 使用webflux响应式开发教程(一)

    什么是webFlux 左侧是传统的基于Servlet的Spring Web MVC框架,右侧是5.0版本新引入的基于Reactive Streams的Spring WebFlux框架,从上到下依次是R ...

  2. SpringBoot使用WebFlux响应式编程操作数据库

    这一篇文章介绍SpringBoot使用WebFlux响应式编程操作MongoDb数据库. 前言 在之前一篇简单介绍了WebFlux响应式编程的操作,我们在来看一下下图,可以看到,在目前的Spring ...

  3. springboot2 webflux 响应式编程学习路径

    springboot2 已经发布,其中最亮眼的非webflux响应式编程莫属了!响应式的weblfux可以支持高吞吐量,意味着使用相同的资源可以处理更加多的请求,毫无疑问将会成为未来技术的趋势,是必学 ...

  4. [转]springboot2 webflux 响应式编程学习路径

    原文链接 spring官方文档 springboot2 已经发布,其中最亮眼的非webflux响应式编程莫属了!响应式的weblfux可以支持高吞吐量,意味着使用相同的资源可以处理更加多的请求,毫无疑 ...

  5. 《微信小程序七日谈》- 第二天:你可能要抛弃原来的响应式开发思维

    <微信小程序七日谈>系列文章: 第一天:人生若只如初见: 第二天:你可能要抛弃原来的响应式开发思维: 第三天:玩转Page组件的生命周期: 第四天:页面路径最多五层?导航可以这么玩 上篇文 ...

  6. 基于screen.width的伪响应式开发

    一.站在用户的角度看问题 一个用户,访问一个web页面的真实场景是怎样的呢? 下面是某用户访问某站点的一个场景: 1. 小明打开了自己的电脑,访问了鑫空间-鑫生活: 2. 小明体内洪荒之力无法控制,疯 ...

  7. 移动端开发之响应式开发和bootstrap基础

    响应式开发 (就是利用媒体查询针对不同宽度的设备进行布局和样式的设置,从而设配不同设备的目的) 响应式布局容器响应式需要一个父级作为布局容器,来配合子级元素来实现变化效果 原理:不同屏幕下,通过媒体查 ...

  8. 带你玩转JavaWeb开发之五-如何完成响应式开发页面

    响应式页面开发 使用BootStrap开发一个响应式的页面出来 响应式开发就是同一个页面在PC端与手机端Pad端显示不同的效果,以给用户更好的体验 需求分析 开发一套页面,让用户能够在PC端, Pad ...

  9. 移动端使用rem同时适应安卓ios手机原理解析,移动端响应式开发

    rem单位大家可能已经很熟悉,rem是随着html的字体大小来显示代表宽度的方法,我们怎样进行移动端响应式开发呢 浏览器默认的字体大小为16px 及1rem 等于 16px 如果我们想要使1rem等于 ...

随机推荐

  1. 初识express

    初识Express 1.简介: express是基于Nodejs平台的快速,开放,极简的web开发框架 2.安装 npm install express --save 3.Hello world: c ...

  2. golang (3) 编译不同的平台文件

    Golang 支持在一个平台下生成另一个平台可执行程序的交叉编译功能. Mac下编译Linux, Windows平台的64位可执行程序: CGO_ENABLED=0 GOOS=linux GOARCH ...

  3. 小程序点击清除input内的内容不生效

    如下图,点击右侧的按钮清除input的内容,当获取焦点时点击按钮是会穿透的清除不了input,使用cover-image和cover-view页面不起作用 解决办法:input在左侧,按钮在右侧使他们 ...

  4. lua-nginx-module模块常用命令

    ngx.location.capture 用法: local res = ngx.location.capture(uri, options) 发起一个同步非阻塞的nginx子请求,uri是inter ...

  5. Robot Framework_Ride(Edit标签)

    前言 RIDE 作为 Robot Framework 的“脸面”,虽然我们已经可以拿它来创建和运行测试了,但我们对它的认识并不全面,这一小节我们将了解这个工具的使用 Edit标签 下面我们来看一看测试 ...

  6. c++ 网络编程(九)LINUX/windows-IOCP模型 多线程超详细教程及多线程实现服务端

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9661012.html 先讲Linux下(windows下在后面可以直接跳到后面看): 一.线程 ...

  7. ES6基本语法之let和const

    1.var可以重复声明 var a = 12; var a = 5; alert(a) //5 2.var无法限制修改 如:PI = 3.1415: 3.var没有块级作用域 { } 像: if(){ ...

  8. 关于DeferredResult的思考

    使用SpringBoot搭建web程序,里面内置了tomcat,一般都不会关心内部实现机制,上来就可以写程序,并且可以跑起来.但是是思考了每次的请求是如何工作的. 简单的来讲就是tomcat是将每次请 ...

  9. 攻克数据库核心技术壁垒,实现百万级QPS的高吞吐

    CynosDB是腾讯云自研的新一代高性能高可用的企业级分布式云数据库.融合了传统数据库.云计算与新硬件的优势,100%兼容开源数据库,百万级QPS的高吞吐,不限存储,价格仅为商用数据库的1/10. C ...

  10. HDU 5698——瞬间移动——————【逆元求组合数】

    瞬间移动 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submis ...