第16章-使用Spring MVC创建REST API

1 了解REST

1.1 REST的基础知识

REST与RPC几乎没有任何关系。RPC是面向服务的,并关注于行为和动作;而REST是面向资源的,强调描述应用程序的事物和名词。
为了理解REST是什么,我们将它的首字母缩写拆分为不同的构成部分:

  • 表述性(Representational):REST资源实际上可以用各种形式来进行表述,包括XML、JSON(JavaScript Object Notation)甚至HTML——最适合资源使用者的任意形式;
  • 状态(State):当使用REST的时候,我们更关注资源的状态而不是对资源采取的行为;
  • 转移(Transfer):REST涉及到转移资源数据,它以某种表述性形式从一个应用转移到另一个应用。

REST中会有行为,它们是通过HTTP方法来定义的。具体来讲,也就是GET、POST、PUT、DELETE、PATCH以及其他的HTTP方法构成了REST中的动作。这些HTTP方法通常会匹配为如下的CRUD动作:

  • Create:POST
  • Read:GET
  • Update:PUT或PATCH
  • Delete:DELETE

1.2 Spring是如何支持REST的

当前的4.0版本中,Spring支持以下方式来创建REST资源:

  • 控制器可以处理所有的HTTP方法,包含四个主要的REST方法:GET、PUT、DELETE以及POST。Spring 3.2及以上版本还支持PATCH方法;
  • 借助@PathVariable注解,控制器能够处理参数化的URL(将变量输入作为URL的一部分);
  • 借助Spring的视图和视图解析器,资源能够以多种方式进行表述,包括将模型数据渲染为XML、JSON、Atom以及RSS的View实现;
  • 可以使用ContentNegotiatingViewResolver来选择最适合客户端的表述;
  • 借助@ResponseBody注解和各种HttpMethodConverter实现,能够替换基于视图的渲染方式;
  • 类似地,@RequestBody注解以及HttpMethodConverter实现可以将传入的HTTP数据转化为传入控制器处理方法的Java对象;
  • 借助RestTemplate,Spring应用能够方便地使用REST资源。

2 创建第一个REST端点

Spring提供了两种方法将资源的Java表述形式转换为发送给客户端的表述形式:

  • 内容协商(Content negotiation):选择一个视图,它能够将模型渲染为呈现给客户端的表述形式;
  • 消息转换器(Message conversion):通过一个消息转换器将控制器所返回的对象转换为呈现给客户端的表述形式。

2.1 协商资源表述

在面向人类访问的Web应用程序中,选择的视图通常来讲都会渲染为HTML。视图解析方案是个简单的一维活动。如果根据视图名匹配上了视图,那这就是我们要用的视图了。

当要将视图名解析为能够产生资源表述的视图时,我们就有另外一个维度需要考虑了。视图不仅要匹配视图名,而且所选择的视图要适合客户端。如果客户端想要JSON,那么渲染HTML的视图就不行了。

Spring的ContentNegotiatingViewResolver是一个特殊的视图解析器,它考虑到了客户端所需要的内容类型。
要理解ContentNegotiatingViewResolver是如何工作的,这涉及内容协商的两个步骤:

  • 1.确定请求的媒体类型;
  • 2.找到适合请求媒体类型的最佳视图。

确定请求的媒体类型
ContentNegotiatingViewResolver将会考虑到Accept头部信息并使用它所请求的媒体类型,但是它会首先查看URL的文件扩展名。如果URL在结尾处有文件扩展名的话,ContentNegotiatingViewResolver将会基于该扩展名确定所需的类型。如果扩展名是“.json”的话,那么所需的内容类型必须是“application/json”。如果扩展名是“.xml”,那么客户端请求的就是“application/xml”。当然,“.html”扩展名表明客户端所需的资源表述为HTML(text/html)。

如果根据文件扩展名不能得到任何媒体类型的话,那就会考虑请求中的Accept头部信息。在这种情况下,Accept头部信息中的值就表明了客户端想要的MIME类型,没有必要再去查找了。

最后,如果没有Accept头部信息,并且扩展名也无法提供帮助的话,ContentNegotiatingViewResolver将会使用“/”作为默认的内容类型,这就意味着客户端必须要接收服务器发送的任何形式的表述。

一旦内容类型确定之后,ContentNegotiatingViewResolver就该将逻辑视图名解析为渲染模型的View。与Spring的其他视图解析器不同,ContentNegotiatingViewResolver本身不会解析视图。而是委托给其他的视图解析器,让它们来解析视图。

影响媒体类型的选择
在上述的选择过程中,我们阐述了确定所请求媒体类型的默认策略。但是通过为其设置一个ContentNegotiationManager,我们能够改变它的行为。借助Content-NegotiationManager我们所能做到的事情如下所示:

  • 指定默认的内容类型,如果根据请求无法得到内容类型的话,将会使用默认值;
  • 通过请求参数指定内容类型;
  • 忽视请求的Accept头部信息;
  • 将请求的扩展名映射为特定的媒体类型;
  • 将JAF(Java Activation Framework)作为根据扩展名查找媒体类型的备用方案。

有三种配置ContentNegotiationManager的方法:

  • 直接声明一个ContentNegotiationManager类型的bean;
  • 通过ContentNegotiationManagerFactoryBean间接创建bean;
  • 重载WebMvcConfigurerAdapter的configureContentNegotiation()方法。

直接创建ContentNegotiationManager有一些复杂,除非有充分的原因,否则我们不会愿意这样做。后两种方案能够让创建ContentNegotiationManager更加简单。

  • 使用XML配置ContentNegotiationManager
<bean id="contentNegotiationManager"class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean"p:defaultContentType ="application/json">
</bean>
  • 使用Java配置configureContentNegotiation
    @Overridepublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer.defaultContentType(MediaType.APPLICATION_JSON);}

现在,我们已经有了ContentNegotiationManagerbean,接下来就需要将它注入到ContentNegotiatingViewResolver的contentNegotiationManager属性中。

    @Beanpublic ViewResolver cnViewResolver(ContentNegotiationManager cnm) {ContentNegotiatingViewResolver cnvr =new ContentNegotiatingViewResolver();cnvr.setContentNegotiationManager(cnm);return cnvr;}

如下的程序清单是一个非常简单的配置样例,当我使用ContentNegotiatingViewResolver的时候,通常会采用这种用法:它默认会使用HTML视图,但是对特定的视图名称将会渲染为JSON输出。
775861-20180719094717857-1538841811.jpg

如果逻辑视图的名称为“spittles”,那么我们所配置的BeanNameViewResolver将会解析spittles()方法中所声明的View。这是因为bean名称匹配逻辑视图的名称。如果没有匹配的View的话,ContentNegotiatingViewResolver将会采用默认的行为,将其输出为HTML。

ContentNegotiatingViewResolver的优势与限制
ContentNegotiatingViewResolver最大的优势在于,它在Spring MVC之上构建了REST资源表述层,控制器代码无需修改。相同的一套控制器方法能够为面向人类的用户产生HTML内容,也能针对不是人类的客户端产生JSON或XML。

ContentNegotiatingViewResolver还有一个相关的小问题,所选中的View会渲染模型给客户端,而不是资源。这里有个细微但很重要的区别。当客户端请求JSON格式的Spittle对象列表时,客户端希望得到的响应可能如下所示:
775861-20180719094718172-2019523824.jpg
775861-20180719094718510-262218164.jpg

因为有这些限制,我通常建议不要使用ContentNegotiatingViewResolver。我更加倾向于使用Spring的消息转换功能来生成资源表
述。接下来,我们看一下如何在控制器代码中使用Spring的消息转换器。

2.2 使用HTTP信息转换器

消息转换(message conversion)提供了一种更为直接的方式,它能够将控制器产生的数据转换为服务于客户端的表述形式。当使用消息转换功能时,DispatcherServlet不再需要那么麻烦地将模型数据传送到视图中。实际上,这里根本就没有模型,也没有视图,只有控制器产生的数据,以及消息转换器(message converter)转换数据之后所产生的资源表述。

表16.1 Spring提供了多个HTTP信息转换器,用于实现资源表述与各种Java类型之间的互相转换
775861-20180719094718988-1226870273.jpg
775861-20180719094719839-944419153.jpg
在响应体中返回资源状态
正常情况下,当处理方法返回Java对象(除String外或View的实现以外)时,这个对象会放在模型中并在视图中渲染使用。但是,如果使用了消息转换功能的话,我们需要告诉Spring跳过正常的模型/视图流程,并使用消息转换器。有不少方式都能做到这一点,但是最简单的方法是为控制器方法添加@ResponseBody注解。

@ResponseBody注解会告知Spring,我们要将返回的对象作为资源发送给客户端,并将其转换为客户端可接受的表述形式。更具体地讲,DispatcherServlet将会考虑到请求中Accept头部信息,并查找能够为客户端提供所需表述形式的消息转换器。消息转换器会将控制器返回的Spittle列表转换为JSON文档,并将其写入到响应体中。响应大致会如下所示:

  @RequestMapping(method=RequestMethod.GET, produces = "application/json")public @ResponseBody  List<Spittle> spittles(@RequestParam(value="max", defaultValue=MAX_LONG_AS_STRING) long max,@RequestParam(value="count", defaultValue="20") int count) {return spittleRepository.findSpittles(max, count);}

775861-20180719094720561-802206226.jpg
谈及Accept头部信息,请注意getSpitter()的@RequestMapping注解。在这里,我使用了produces属性表明这个方法只处理预期输出为JSON的请求。也就是说,这个方法只会处理Accept头部信息包含“application/json”的请求。其他任何类型的请求,即使它的URL匹配指定的路径并且是GET请求也不会被这个方法处理。这样的请求会被其他的方法来进行处理(如果存在适当方法的话),或者返回客户端HTTP 406(Not Acceptable)响应。

在请求体中接收资源状态
@ResponseBody能够告诉Spring在把数据发送给客户端的时候,要使用某一个消息器,与之类似,@RequestBody也能告诉Spring查找一个消息转换器,将来自客户端的资源表述转换为对象。例如,假设我们需要一种方式将客户端提交的新Spittle保存起来。我们可以按照如下的方式编写控制器方法来处理这种请求:

  @RequestMapping(method=RequestMethod.POST,consumes = "application/json")public @ResponseBody  Spittle saveSpittle(@RequestBody Spittle spittle) {return spittleRepository.save(spittle);}

@RequestMapping表明它只能处理“/spittles”(在类级别的@RequestMapping中进行了声明)的POST请求。

@RequestMapping有一个consumes属性,我们将其设置为“application/json”。consumes属性的工作方式类似于produces,不过它会关注请求的Content-Type头部信息。它会告诉Spring这个方法只会处理对“/spittles”的POST请求,并且要求请求的Content-Type头部信息为“application/json”。

为控制器默认设置消息转换
Spring 4.0引入了@RestController注解,能够在这个方面给我们提供帮助。如果在控制器类上使用@RestController来代替@Controller的话,Spring将会为该控制器的所有处理方法应用消息转换功能。我们不必为每个方法都添加@ResponseBody了。

3 提供资源之外的其他内容

3.1 发送错误信息到客户端

@RequestMapping(value="/{spittleId}", method=RequestMethod.GET)public @ResponseBody Spittle spittleById(@PathVariable("spittleId") long spittleId, {return spittleRepository.findOne(spittleId);}

如果根据给定的ID,无法找到某个Spittle对象的ID属性能够与之匹配,findOne()方法返回null的时候,你觉得会发生什么呢?结果就是spittleById()方法会返回null,响应体为空,不会返回任何有用的数据给客户端。同时,响应中默认的HTTP状态码是200(OK),表示所有的事情运行正常。

现在,我们考虑一下在这种场景下应该发生什么。至少,状态码不应该是200,而应该是404(Not Found),告诉客户端它们所要求的内容没有找到。如果响应体中能够包含错误信息而不是空的话就更好了。

Spring提供了多种方式来处理这样的场景:

  • 使用@ResponseStatus注解可以指定状态码;
  • 控制器方法可以返回ResponseEntity对象,该对象能够包含更多响应相关的元数据;
  • 异常处理器能够应对错误场景,这样处理器方法就能关注于正常的状况。

使用ResponseEntity
作为@ResponseBody的替代方案,控制器方法可以返回一个ResponseEntity对象。ResponseEntity中可以包含响应相关的元数据(如头部信息和状态码)以及要转换成资源表述的对象。

  @RequestMapping(value="/{spittleId}", method=RequestMethod.GET)public ResponseEntity<Spittle> spittle(@PathVariable("spittleId") long spittleId, {Spittle spittle = spittleRepository.findOne(spittleId);HttpStatus status = spittle != null ? HttpStatus.OK : HttpStatus.NOT_FOUND;return new ResponseEntity<Spittle>(spittle, status);}

处理错误
spittleById()方法中的if代码块是处理错误的,但这是控制器中错误处理器(error handler)所擅长的领域。错误处理器能够处理导致问题的场景,这样常规的处理器方法就能只关心正常的逻辑处理路径了。

我们重构一下代码来使用错误处理器。首先,定义能够对应SpittleNotFoundException的错误处理器:

  @ExceptionHandler(SpittleNotFoundException.class)@ResponseStatus(HttpStatus.NOT_FOUND)public @ResponseBody Error spittleNotFound(SpittleNotFoundException e) {long spittleId = e.getSpittleId();return new Error(4, "Spittle [" + spittleId + "] not found");}

其中涉及的类:

  • Error类
public class Error {private int code;private String message;public Error(int code, String message) {this.code = code;this.message = message;}public int getCode() {return code;}public String getMessage() {return message;}}
  • 异常类:
public class SpittleNotFoundException extends RuntimeException {private static final long serialVersionUID = 1L;private long spittleId;public SpittleNotFoundException(long spittleId) {this.spittleId = spittleId;}public long getSpittleId() {return spittleId;}}

我们可以移除掉spittleById()方法中大多数的错误处理代码:

  @RequestMapping(value="/{id}", method=RequestMethod.GET, produces="application/json")public Spittle spittleById(@PathVariable Long id) {Spittle spittle = spittleRepository.findOne(id);if (spittle == null) {throw new SpittleNotFoundException(id);}return spittle;}

以上,现在我们已经知道spittleById()将会返回Spittle并且HTTP状态码始终会是200(OK),那么就可以不再使用ResponseEntity,而是将其替换为@ResponseBody。如果控制器类上使用了@RestController,我们不再需要@ResponseBody。

3.2 在响应中设置头部信息

客户端知道新创建了资源,你觉得客户端会不会感兴趣新创建的资源在哪里呢?

当创建新资源的时候,将资源的URL放在响应的Location头部信息中,并返回给客户端是一种很好的方式。因此,我们需要有一种方式来填充响应头部信息,此时我们的老朋友ResponseEntity就能提供帮助了。

如下的程序清单展现了一个新版本的saveSpittle(),它会返回ResponseEntity用来告诉客户端新创建的资源。

  @RequestMapping(method=RequestMethod.POST, consumes="application/json")@ResponseStatus(HttpStatus.CREATED)public ResponseEntity<Spittle> saveSpittle(@RequestBody Spittle spittle, UriComponentsBuilder ucb) {Spittle saved = spittleRepository.save(spittle);HttpHeaders headers = new HttpHeaders();URI locationUri = ucb.path("/spittles/").path(String.valueOf(saved.getId())).build().toUri();headers.setLocation(locationUri);ResponseEntity<Spittle> responseEntity = new ResponseEntity<Spittle>(saved, headers, HttpStatus.CREATED);return responseEntity;}

在处理器方法所得到的UriComponentsBuilder中,会预先配置已知的信息如host、端口以及Servlet内容。

注意,路径的构建分为两步。第一步调用path()方法,将其设置为“/ spittles/”,也就是这个控制器所能处理的基础路径。然后,在第二次调用path()的时候,使用了已保存Spittle的ID。我们可以推断出来,每次调用path()都会基于上次调用的结果。在路径设置完成之后,调用build()方法来构建UriComponents对象,根据这个对象调用toUri()就能得到新创建Spittle的URI。

4 编写REST客户端

4.1 了解RestTemplate的操作

RestTemplate定义了36个与REST资源交互的方法,其中的大多数都对应于HTTP的方法。但是,在本章中我没有足够的篇幅涵盖所有的36个方法。

除了TRACE以外,RestTemplate涵盖了所有的HTTP动作。除此之外,execute()和exchange()提供了较低层次的通用方法来使用任意的HTTP方法。
表16.2中的大多数操作都以三种方法的形式进行了重载:

  • 一个使用java.net.URI作为URL格式,不支持参数化URL;
  • 一个使用String作为URL格式,并使用Map指明URL参数;
  • 一个使用String作为URL格式,并使用可变参数列表指明URL参数。

表16.2 RestTemplate定义了11个独立的操作,而每一个都有重载,这样一共是36个方法
775861-20180719094721062-333363998.jpg
775861-20180719094721405-1489043671.jpg

4.2 GET资源

让我们首先看一下稍微简单的getForObject()方法。然后再看看如何使用getForEntity()方法来从GET响应中获取更多的信息。

4.3 检索资源

775861-20180719094721770-1019108241.jpg

4.4 抽取响应的元数据

775861-20180719094722076-1952939464.jpg

4.5 PUT资源

775861-20180719094722373-2023305029.jpg

4.6 DELETE资源

775861-20180719094722618-1413328172.jpg

4.7 POST资源数据

postForObject()和postForEntity()对POST请求的处理方式与发送GET请求的getForObject()和getForEntity()方法是类似的。另一个方法是getForLocation(),它是POST请求所特有的。

4.8 在POST请求中获取响应对象

775861-20180719094722913-1073021698.jpg

775861-20180719094723195-660323136.jpg

4.9 在POST请求后获取资源位置

775861-20180719094723458-1195072549.jpg

4.10 交换资源

不同于getForEntity()——或getForObject()——exchange()方法允许在请求中设置头信息。
如果不指明头信息,exchange()对Spitter的GET请求会带有如下的头信息:
775861-20180719094723735-188503189.jpg
假设我们希望服务端以JSON格式发送资源。在这种情况下,我们需要将“application/json”设置为Accept头信息的唯一值。设置请求头信息是很简单的,只需构造发送给exchange()方法的HttpEntity对象即可,HttpEntity中包含承载头信息的MultiValueMap:
775861-20180719094724055-76476869.jpg
现在,我们可以传入HttpEntity来调用exchange():
775861-20180719094724386-127887827.jpg

源码

https://github.com/myitroad/spring-in-action-4/tree/master/Chapter_16

附件列表

  • cnm.jpg
  • converter1.jpg
  • converter2.jpg
  • converteRslt.jpg
  • defHeader.jpg
  • delRsc.jpg
  • exchange.jpg
  • getRscEntity.jpg
  • getRscObject.jpg
  • postForEntity.jpg
  • postForLoc.jpg
  • postForObj.jpg
  • putRsc.jpg
  • resp1.jpg
  • resp2.jpg
  • restTempOper1.jpg
  • restTempOper2.jpg
  • setHeader.jpg

 

转载于:https://www.cnblogs.com/myitroad/p/9334090.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366428.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Apache Mahout创建在线推荐系统

最近&#xff0c; 我们一直在为Yap.TV实施推荐系统&#xff1a;在安装应用程序并转到“ Just for you”选项卡后&#xff0c;您可以看到它的运行情况。 我们以Apache Mahout为基础进行建议。 Mahout是一个“可扩展的机器学习库”&#xff0c;其中包含使用协作过滤算法的基于用户…

linux mono mysql_LJMM平台( Linux +Jexus+MySQL+mono) 上使用MySQL的简单总结

近准备把PDF.NET框架的开源项目“超市管理系统”移植到Linux上跑(演示地址&#xff1a;http://221.123.142.196)&#xff0c;使用Jexus服务器和MySQL数据库&#xff0c;相对使用SQLite而言&#xff0c;用MySQL问题比较多&#xff0c;但最后还是一一解决了&#xff0c;先总结如下…

node中的缓存机制

缓存是node开发中一个很重要的概念&#xff0c;它应用在很多地方&#xff0c;例如&#xff1a;浏览器有缓存、DNS有缓存、包括服务器也有缓存。 一、缓存作用 那缓存是为了做什么呢&#xff1f; 1.为了提高速度&#xff0c;提高效率。 2.减少数据传输&#xff0c;节省网费。 …

《H5 移动营销设计指南》 读书笔记整理

一个前端工程师最近迷上了营销类的H5页面&#xff0c;被五花八门的H5页面迷的眼花缭乱&#xff0c;兴趣使然&#xff0c;于是买了一本《H5 营销设计指南》&#xff0c;看完以后对营销类的H5页面有了更深的理解&#xff0c;感觉很实在&#xff0c;所以参考读书笔记整理成PPT分享…

mysql-plus多数据库_IDEA项目搭建九——MybatisPlus多数据库实现

一、简介MybatisPlus中引用多数据库时&#xff0c;传统的配置就失效了&#xff0c;需要单独写配置来实现&#xff0c;下面就说一下具体应该如何操作二、引入MybatisPlus多数据源配置还是先看一下我的项目结构&#xff0c;Model是单独的模块&#xff0c;请自行创建1、创建一个Ma…

数字逻辑基础篇1

1. 双阈值准则在模拟条件下&#xff0c;假设点亮灯泡需要1.7V以上电压。抽象为数字电路&#xff0c;可以认为&#xff1a; U>1.7V U1 U<1.7V U0 这种条件称之为单阈值&#xff08;1.7&#xff09;&#xff0c;但是单阈值导致的问题是&#xff1a; 电压在1.7V附近…

Neo4j:在Neo4j浏览器的帮助下探索新数据集

当我查看一个新的Neo4j数据库时&#xff0c;发现困难之一是确定其中包含的数据的结构。 我习惯于关系数据库&#xff0c;在该数据库中您可以轻松地获取表列表和外键&#xff0c;从而使它们彼此连接。 传统上&#xff0c;使用Neo4j时很难做到这一点&#xff0c;但是随着Neo4j浏…

V8 —— 你需要知道的垃圾回收机制

前言V8 blog近日发布了文章描述了“并发标记”的新技术&#xff0c;提升标记过程的效率。并发标记是一个主要用新的平行和并发的垃圾收集器替换旧的垃圾回收器的项目&#xff0c;现在Chrome 64和Node.js v10已经默认启用并发标记。讲解之前我们先回顾一下基本知识点。基本概念 …

词法分析器java_Java代码到底是如何编译成机器指令的。

原文地址&#xff1a;https://mp.weixin.qq.com/s/XH-JajAne0O7_yCYE5wBbg作者&#xff1a;Hollis在《Java代码的编译与反编译》中&#xff0c;有过关于Java语言的编译和反编译的介绍。我们可以通过javac命令将Java程序的源代码编译成Java字节码&#xff0c;即我们常说的class文…

python中的PEP是什么?怎么理解?(转)

PEP是什么&#xff1f; PEP的全称是Python Enhancement Proposals&#xff0c;其中Enhancement是增强改进的意思&#xff0c;Proposals则可译为提案或建议书&#xff0c;所以合起来&#xff0c;比较常见的翻译是Python增强提案或Python改进建议书。 我个人倾向于前一个翻译&…

2017前端技术大盘点

前言 临近2017的尾声&#xff0c;总是希望来盘点一下这一年中前端的发展。到目前为止&#xff0c;前端的井喷期也快临近尾声了。并不像几年前一样&#xff0c;总是会有层出不穷的新东西迸发出来。同时&#xff0c;前端技术也慢慢的趋于稳固&#xff0c;自成一套体系。如果你喜…

jenkins pipeline api获取stage的详细信息_Jenkins + Docker 助力 Serverless 应用构建与部署...

本文来源&#xff1a; ServerlessLife 公众号近日&#xff0c;使用 Serverless 开发了一个应用。其中 CI/CD&#xff0c;是需要考虑的一个问题。这里用到了 Jenkins 和 Docker。并且 Jenkins Pipeline 运行在容器中。本文将介绍如何使用 Jenkins 和 Docker 构建并部署 Serverle…

项目本地部署

1.将数据库导出&#xff0c;并导入到本地 exp dgpdg/pass192.168.1.33/ORCL fileD:\gd_base.dmp logD:\gd_base.log&#xff08;不要加fully&#xff0c;会把整个数据库下所有用户的表倒下来&#xff09; imp dgpdg/pass127.0.0.1/orcl file"D:\gd_base.dmp" log&quo…

命名空间不能直接包含字段或方法之类的成员是什么意思_Python 学习笔记之类与实例...

Python 学习笔记之类与实例一、定义1.1、定义类 (class) 封装一组相关数据&#xff0c;使之成为一个整体&#xff0c;并使用一种方法持续展示和维护。这有点像把零件组装成整车提供给用户&#xff0c;无须了解汽车的内部结构和工作原理&#xff0c;只要知道方向盘&#xff0c;刹…

跨平台开发框架 Lynx 初探

跨平台开发是目前开发较热门的方向&#xff0c;React Native 在这方面取得了很大的成功&#xff0c;同时 Flutter 也获得了非常多的关注。React Native 采用 Web 框架开发并使用 Native UI 进行渲染&#xff0c;很大程度上降低了 Native 开发的门槛并且提高迭代的效率&#xff…

ajax包含mysql吗_php 实例ajax与mysql怎么只查询出一条数据?

http://www.runoob.com/php/php...使用这个实例操作之后为什么只显示一条数据&#xff0c;如何让符合条件的数据全部显示出来如&#xff0c;我使用的查询字段是yesterday_str&#xff0c;查询2017-04-18这个数据怎么样才能把2017-04-18包含这个的全部数据提取出来&#xff1f;p…

aspx写入mysql_Asp.net用户登陆数据库验证与注册写入数据库

1.思路与效果图Index.aspx注册注册成功登陆登陆验证通过进入内容页1登陆没通过验证思路&#xff1a;首先建一个Sqlserver数据库Student,再建一个student表(name,pwd)存放用户名和密码。然后注册功能的实现&#xff1a;通过数据库插入信息到表的Sql语句来实现&#xff0c;成功提…

页面体验提升小技巧—渐进式图片

前端性能方面有许多可优化的点&#xff0c;而这些优化带来的就是用户体验的提升。今天我们要聊的东西并不能给性能带来提升&#xff0c;但却能在一定程度上提升用户的体验。 参考博客 场景&#xff1a;在访问页面的时候如果图片较大或者网速慢的情况我们会看到图片加载起来是有…

微信小程序搭配小白接口,自己没有服务器也能开发哦

这里将重点介绍&#xff0c;在自己没有服务器的情况下&#xff0c;如何在微信小程序里直接调用小白接口。 前提 假设你已经开通微信小程序&#xff0c;如果还没有&#xff0c;可前往微信公众平台开通&#xff1a;https://mp.weixin.qq.com 假设你已经开通小白接口&#xff0c…

怎么将自己做好的网站发布到互联网上呢?

如何将自己的网站上传到网站空间。 1.需要有一个上传网站的软件&#xff0c;在这里推荐大家使用 FTP全称是flashfxp这个软件&#xff0c;这个功能功能齐全而且操作简单。大家可以先去下载一下这个软 件 2. 打开FTP&#xff0c;界面如下 3.我们要点击链接按钮&#xff0c;然后FT…