【SpringBoot】---接口架构风格——RESTful

【SpringBoot】---接口架构风格——RESTful

一、REST——前后台间的通信方式

1、认识REST

​ REST是软件架构的规范体系结构,它将资源的状态以适合客户端的形式从服务器端发送到客户端(或相反方向)。**在REST中,通过URL进行资源定位,用HTTP动作(GET、POST等)描述操作,完成功能。

遵循RESTful风格,可以使得开发的接口通用。

2、REST的特征

  • 客户-服务器:提供服务的服务器和使用服务的客户端需要被隔离对待。
  • 无状态:服务器端不存储客户的请求中的信息,客户的每一个请求必须包含服务器处理该请求所需的所有信息,所有的资源都可以通过URI定位。
  • 可缓存:服务器必须让客户知道请求是否可以被缓存。
  • 统一接口:客户和服务器之间通信的方法必须统一,RESTful风格的数据元操作CRUD分别对应HTTP方法——GET来获取、POST用来新建资源、PUT用来更新资源,DELETE用来删除资源,这样就统一了数据操作的接口。
  • HTTP状态码

3、HTTP方法与CRUD动作映射

RESTful风格使用同一个URL,通过约定不同的HTTP方法来实施不同的业务。

普通网页的CRUD和RESTful风格CRUD的区别

动作 普通CURD的URL 普通CRUD的HTTP方法 Restful的URL Restful的CRUD的HTTP方法
查询 Article/id=1 GET Article/ GET
添加 Article?title=xxx&body=xxx GET/POST Article POST
修改 Article/update?id=xxx GET Article/ PUT或PATCH
删除 Article/delete?id=xxx GET Article/ DELETE

4、实现RESTful风格的数据增加、删除、修改和查询

@RestController和@RequestMapping来实现

  • Value:用来定制URI
  • Method:用来定制HTTP请求方法
  • 通过@PathVariable("")来获取参数
@RequestMapping(Value = "/{id}",method = RequestMethod.DELETE)
public String delete(@PathVariable("id") long id){
    articleRespository.deleteById(id);
    return "success";
}

二、设计统一的RESTful风格的数据接口

1、版本控制

①通过URL

  • 二级目录的方式:

    • http://eg.com/api/v1
      http://eg.com/api/v2
      
  • 二级域名的方式:

    • http://v1.eg.com
      http://v2.eg.com
      

②通过自定义请求头:

自定义头(例如,Accept-version)允许在版本之间保留URL

③通过Accept标头

客户端在请求资源之前,必须要指定特定头,然后API接口负责确定要发送哪个版本的资源

2、过滤信息

​ 如果记录数量很多,则服务器不可能一次都将它们返回给用户。API应该提供参数,实现分页返回结果。

  • ?limit=10:指定返回记录的数量
  • ?page=5&size=10:指定第几页,以及每页的记录数
  • ?search_type=1:指定筛选条件

3、定义统一的返回的格式

为了保障前后端数据交互的顺畅,建议规范数据的返回,并采用固定的数据格式封装。

异常信息:

{
	"code":10001,
	"msg":"异常信息",
	"data":null
}

成功信息:

{
	"code":200,
	"msg":"成功",
	"data":{
	"id":1,
	"name":"longzhiran",
	"age":2
	}
}

4、实例:为手机APP、PC、H5网页提供统一风格的API

①实现响应的枚举类

public enum ExceptionMsg{
    SUCCESS("200","操作成功"),
    FAILED("999999","操作失败");
    
    public ExceptionMsg(String code,String msg){
        this.code = code;
        this.msg = msg;
    }
    
    private String code;
    private String msg;
}

②实现返回的实体对象

实现返回的对象实体,返回Code和Message

public class Response{
    private String rspCode = "200";
    
    prvate String rspMsg = "操作成功";
}

③封装返回的结果0

public class ResponseData extends Response{
    private Object data;
    public ResponseData(Object data){
        this.data = data;
    }
}

④统一处理异常

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.*;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@RestControllerAdvice
public class GlobalExceptionHandler {
    // 日志记录工具
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Map<String, Object> handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        logger.error("缺少请求参数", e);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("rspCode", 400);
        map.put("rspMsg", e.getMessage());
        //发生异常进行日志记录,写入数据库或者其他处理,此处省略
        return map;
    }

    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Map<String, Object> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        logger.error("参数解析失败", e);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("rspCode", 400);
        map.put("rspMsg", e.getMessage());
        //发生异常进行日志记录,写入数据库或者其他处理,此处省略
        return map;
    }
    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Map<String, Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        logger.error("参数验证失败", e);
        BindingResult result = e.getBindingResult();
        FieldError error = result.getFieldError();
        String field = error.getField();
        String code = error.getDefaultMessage();
        String message = String.format("%s:%s", field, code);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("rspCode", 400);
        map.put("rspMsg", message);
        //发生异常进行日志记录,写入数据库或者其他处理,此处省略
        return map;
    }

    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(BindException.class)
    public Map<String, Object> handleBindException(BindException e) {
        logger.error("参数绑定失败", e);
        Map<String, Object> map = new HashMap<String, Object>();
        BindingResult result = e.getBindingResult();
        FieldError error = result.getFieldError();
        String field = error.getField();
        String code = error.getDefaultMessage();
        String message =  String.format("%s:%s", field, code);
        map.put("rspCode", 400);
        map.put("rspMsg",message);
        //发生异常进行日志记录,写入数据库或者其他处理,此处省略
        return map;
    }


    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ConstraintViolationException.class)
    public Map<String, Object> handleServiceException(ConstraintViolationException e) {
        logger.error("参数验证失败", e);
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        ConstraintViolation<?> violation = violations.iterator().next();
        String message = violation.getMessage();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("rspCode", 400);
        map.put("rspMsg", message);
        //发生异常进行日志记录,写入数据库或者其他处理,此处省略
        return map;
    }
    /**
     * 400 - Bad Request
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(ValidationException.class)
    public Map<String, Object> handleValidationException(ValidationException e) {
        logger.error("参数验证失败", e);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("rspCode", 400);
        map.put("rspMsg", e.getMessage());
        //发生异常进行日志记录,写入数据库或者其他处理,此处省略
        return map;
    }

    /**
     * 405 - Method Not Allowed
     */
    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Map<String, Object> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        logger.error("不支持当前请求方法", e);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("rspCode", 405);
        map.put("rspMsg", e.getMessage());
        //发生异常进行日志记录,写入数据库或者其他处理,此处省略
        return map;
    }

    /**
     * 415 - Unsupported Media Type
     */
    @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public Map<String, Object> handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
        logger.error("不支持当前媒体类型", e);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("rspCode", 415);
        map.put("rspMsg", e.getMessage());
        //发生异常进行日志记录,写入数据库或者其他处理,此处省略
        return map;
    }

    /**
     * 自定义异常类
     */
    @ResponseBody
    @ExceptionHandler(BusinessException.class)
    public Map<String, Object> businessExceptionHandler(BusinessException e) {
        logger.error("自定义业务失败", e);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("rspCode", e.getCode());
        map.put("rspMsg", e.getMessage());
        //发生异常进行日志记录,写入数据库或者其他处理,此处省略
        return map;
    }


    /**
     * 获取其它异常。包括500
     *
     * @param e
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = Exception.class)
    public Map<String, Object> defaultErrorHandler(Exception e) {
        logger.error("Exception", e);
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("rspCode", 500);
        map.put("rspMsg", e.getMessage());
        //发生异常进行日志记录,写入数据库或者其他处理,此处省略
        return map;
    }
}

⑤编写测试控制器

@RestController
public class TestController {
    @RequestMapping("/BusinessException")
    public String testResponseStatusExceptionResolver(@RequestParam("i") int i){
        if (i==0){
            throw new BusinessException(600,"自定义业务错误");
        }
        throw new ValidationException();

    }

}

运行项目,访问localhost:8080/BusinessException?i=1

⑥实现数据的增加、删除、修改和查询的控制器

entity.Article

@Entity
@Table(name = "artitcle")
@Data
public class Article {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    private String title;
    private String body;

}

repository.ArticleRepository

import com.example.demo.entity.Article;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

public interface ArticleRepository extends JpaRepository<Article,Long>, JpaSpecificationExecutor<Article> {
    Article findById(long id);

}

result.ExceptionMsg

package com.example.demo.result;
//实现响应的枚举类
public enum ExceptionMsg {
	SUCCESS("200", "操作成功"),
	FAILED("999999","操作失败"),
    ParamError("000001", "参数错误!"),
    FileEmpty("000400","上传文件为空"),
    LimitPictureSize("000401","图片大小必须小于2M"),
    LimitPictureType("000402","图片格式必须为'jpg'、'png'、'jpge'、'gif'、'bmp'")
    ;
   private ExceptionMsg(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    private String code;
    private String msg;
    
	public String getCode() {
		return code;
	}
	public String getMsg() {
		return msg;
	}

    
}

result.ResponseData

package com.example.demo.result;
//返回结果数据格式封装
public class ResponseData extends Response {
    private Object data;

    public ResponseData(Object data) {
        this.data = data;
    }

    public ResponseData(ExceptionMsg msg) {
        super(msg);
    }

    public ResponseData(String rspCode, String rspMsg) {
        super(rspCode, rspMsg);
    }

    public ResponseData(String rspCode, String rspMsg, Object data) {
        super(rspCode, rspMsg);
        this.data = data;
    }

    public ResponseData(ExceptionMsg msg, Object data) {
        super(msg);
        this.data = data;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "ResponseData{" +
                "data=" + data +
                "} " + super.toString();
    }
}

/*return new ResponseData(ExceptionMsg.SUCCESS,"你好");*/

ArticleController

import com.example.demo.entity.Article;
import com.example.demo.repository.ArticleRepository;
import com.example.demo.result.ExceptionMsg;
import com.example.demo.result.Response;
import com.example.demo.result.ResponseData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("article")
public class ArticleController {
    protected Response result(ExceptionMsg msg){
        return new Response(msg);
    }
    protected Response result(){
        return new Response();
    }

    @Autowired
    private ArticleRepository articleRepository;
    @Autowired
    RestTemplateBuilder restTemplateBuilder;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ResponseData  getArticleList() {
        List<Article> list = new ArrayList<Article>(articleRepository.findAll());
        return new ResponseData(ExceptionMsg.SUCCESS,list);

    }

    //增
    @RequestMapping(value = "/", method = RequestMethod.POST)
    public ResponseData add(Article article) {
        articleRepository.save(article);
       // return "{success:true,message: \"添加成功\" }";
        return new ResponseData(ExceptionMsg.SUCCESS,article);
    }


    //删
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    public Response delete(@PathVariable("id") long id) {

     /*   RestTemplate client= restTemplateBuilder.build();
        String uri = "http://localhost:8080" + "/{id}";
        Map map= new HashMap();
        map. put ("orderid",id);
        Void article = client.delete(uri,map,id);*/
        articleRepository.deleteById(id);

        return result(ExceptionMsg.SUCCESS);
        //return new ResponseData(ExceptionMsg.SUCCESS,"");
      }


    //改
    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    public ResponseData update(Article model) {
        articleRepository.save(model);
        return new ResponseData(ExceptionMsg.SUCCESS,model);
    }

    //查
    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public ResponseData findArticle(@PathVariable("id") Integer id) throws IOException {
              Article article = articleRepository.findById(id);
        if (article != null) {
            return new ResponseData(ExceptionMsg.SUCCESS,article);
        }
        return new ResponseData(ExceptionMsg.FAILED,article);
    }
    //查
    @RequestMapping(value = "/re/{id}", method = RequestMethod.GET)
    public Article findArticled(@PathVariable("id") Integer id) throws IOException {
        RestTemplate client= restTemplateBuilder.build();
        String uri = "http://localhost:8080/article/"+id;
        System.out.println(uri);
        Article article = client.getForObject (uri,Article.class,id) ;

        return article;
    }
}

通过PostMan测试接口即可,这里持久层模板用的是JPA。

三、用Swagger实现接口文档

1、配置Swagger

①添加Swagger依赖

在pom.xml文件中加入Swagger2的依赖

<!--Swagger依赖-->
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<version>2.9.2</version>
</dependency>
<!--Swagger-UI依赖 -->
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>2.9.2</version>
</dependency>

②创建Swagger配置类

创建Swagger配置类,完成相关的配置项。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

/**
 * Swagger 配置文件
 */
@Configuration
public class SwaggerConfig {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))

                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title(" RESTful APIs")
                .description("RESTful APIs")
                .termsOfServiceUrl("http://localhost:8080/")
                .contact("long")
                .version("1.0")
                .build();
    }
}

代码解释:

  • @Configuration:让Spring来加载该配置类
  • @EnableSwagger2:启用Swagger2.createRestApi函数创建Docket的Bean
  • apiInfo():用来展示该APi的基本信息
  • select():返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现。
  • apis(RequestHandlerSelectors.basePackage()):配置包扫描路径。Swagger会扫描包下所有Controller定义的API,并产生文档内容。如果不想产生API,则使用注解@ApiIgnore。

2、编写接口文档

​ 在完成了上述的配置之后,即生成了文档,但是这样生成的文档主要针对请求本身,而描述自动根据方法等名产生,对用户并不友好。所以,通常需要自己增加一些说明以丰富文档内容。可以通过一下注解来加以说明。

  • @Api:描述类/接口的主要用途
  • @ApiOperation:描述方法用途,给API增加说明
  • @ApiImplcitParam:描述方法的参数,给参数增加说明
  • @ApiImplicitParams:描述方法的参数(Multi-Params),给参数增加说明
  • @ApiIgnore:忽略某类/方法/参数的文档
@RestController
public class HelloWorldController {
    @ApiOperation(value = "hello", notes = "notes ")
    @RequestMapping("/hello")
    public String hello() throws Exception {
        return "HelloWorld ,Spring Boot!";
    }
    //使用该注解忽略这个API
    @ApiIgnore
    @RequestMapping(value = "/ignoreApi")
    public String  ignoreApi() {
        return "HelloWorld ,Spring Boot!";
    }

四、用RestTemplate发送请求

在Java应用程序中访问RESTful服务,可以使用Apache的HttpClient来实现。不过次方法使用起来太过于繁琐,Spring提供了一种简单便捷的模板类——RestTemplate来进行操作。

RestTemplate用于同步Client端的核心类,简化与HTTP服务的通信。在默认情况下,RestTemplate默认依赖JDK的HTTP连接工具。亦可以通过setRequestFactory属性切换到不同的HTTP源,比如Apache HttpComponents、Netty和OkHttp。

RestTemplate默认使用HttpMessageConverter将HTTP消息转换成POJO,或从POJO转换成HTTP消息,默认情况下会注册MIME类型的转换器,但也可以通过setMessageConverters注册其他类型的转换器。

1、用RestTemplate发送GET请求

​ 可以通过getForEntity和getForObject两种方式

①创建测试实体

public class User {
    private long id;
    private String name;

    public User() {
    }

    public User(long id, String name) {
        this.id = id;
        this.name = name;

    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

②创建测试的API

package com.example.demo.controller;

import com.example.demo.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;

@RestController
public class TestController {

    @RequestMapping(value = "/getparameter", method = RequestMethod.GET)
    public User getparameter(User user) {
        return user;
    }

    @RequestMapping(value = "/getuser1", method = RequestMethod.GET)
    public User user1() {
        return new User(1, "zhonghua");
    }

    @RequestMapping(value = "/postuser", method = RequestMethod.POST)
    public User postUser(User user) {
        System.out.println("name:" + user.getName());
        System.out.println("id:" + user.getId());
        return user;
    }

}

③使用getForEntity测试

a.返回String,不带参数的例子。
package com.example.demo.controller;

import com.example.demo.entity.User;
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.boot.web.client.RestTemplateBuilder;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;

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

import static org.junit.Assert.*;


@SpringBootTest
@RunWith(SpringRunner.class)
public class GetTest {
    @Autowired
    RestTemplateBuilder restTemplateBuilder;
    //返回String,不带参数
    @Test
    public void nparameters() {
        RestTemplate client= restTemplateBuilder.build();
        ResponseEntity<String> responseEntity = client.getForEntity("http://localhost:8080/getuser1", String.class);
        System.out.println(responseEntity.getBody());
    }

}

运行测试单元,控制台输出结果:

{"id":1,"name":"zhonghua"}
b.返回String,带参数的例子。
@Test
public void withparameters1() {
    RestTemplate client= restTemplateBuilder.build();
    ResponseEntity<String> responseEntity = client.getForEntity("http://localhost:8080/getparameter?			name={1}&id={2}", String.class, "hua",2);
    System.out.println(responseEntity.getBody());
}

运行测试单元,控制台输入结果:

{"id":2,"name":"hua"}
//返回String,带参数
    @Test
    public void withparameters2() {
        RestTemplate client= restTemplateBuilder.build();
        Map<String, String> map = new HashMap<>();
        map.put("name", "zhonghuaLong");
        ResponseEntity<String> responseEntity = client.getForEntity("http://localhost:8080/getparameter?name={name}&id=3", String.class, map);
        System.out.println(responseEntity.getBody());
    }

使用name={name}这种形式。最后一个参数是一个map,map的key即为前边占位符的名字,map的value为参数值。

c.返回对象
@Test
public void restUser1() {
    RestTemplate client= restTemplateBuilder.build();
    ResponseEntity<User> responseEntity = client.getForEntity("http://localhost:8080/getuser1", 				User.class);
    System.out.println(responseEntity.getBody().getId());
    System.out.println(responseEntity.getBody().getName());
}

④使用getForObject

​ getForObject函数是对getForEntity函数的进一步封装。如果只关注返回消息体的内容,而对其他信息都不关注,则可以使用getForObject。

@Test
public void  getForObject() {
    RestTemplate client= restTemplateBuilder.build();
    User user = client.getForObject("http://localhost:8080/getuser1", User.class);
    System.out.println(user.getName());
}

2、用RestTemplate发送POST请求

​ POST请求可以通过postForEntity、postForObject、postForLocation、exchange四种方法来发起。

注意:用上述三种方法传递参数的时候,Map不能被定义为HashMap、LinkedHashMap,而应该被定义为LinkedMultiValueMap,这样参数才能成功传递到后台

①使用postForEntity

package com.example.demo.controller;

import com.example.demo.entity.User;
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.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.client.RestTemplate;

import java.net.URI;

import static org.junit.Assert.*;
@SpringBootTest
@RunWith(SpringRunner.class)
public class PostTest {
    @Autowired
    RestTemplateBuilder restTemplateBuilder;
    RestTemplate restTemplate = new RestTemplate();
    @Test
    public void postForEntity() {
        //RestTemplate client= restTemplateBuilder.build();
		// 封装参数,千万不要替换为Map与HashMap,否则参数无法传递
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
        paramMap.add("name", "longzhiran");
        paramMap.add("id", 4);
     /*   User user = new User();
        user.setName("hongwei");
        user.setId(4);*/
        //方法的第一参数表示要调用的服务的地址
        //方法的第二个参数表示上传的参数
        //方法的第三个参数表示返回的消息体的数据类型
        ResponseEntity<User> responseEntity = restTemplate.postForEntity("http://localhost:8080/postuser", 			paramMap, User.class);
        System.out.println( responseEntity.getBody().getName());
    }
}
  • restTemplate.postForEntity("url",paramMap,User.class):参数分别表示要调用的服务的地址、上传的参数、返回的消息体的数据类型。

②使用postForObject

@Test
public void postForObject() {
    // 封装参数,千万不要替换为Map与HashMap,否则参数无法传递
    MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
    paramMap.add("name", "longzhonghua");
    paramMap.add("id", 4);
    RestTemplate client = restTemplateBuilder.build();
    String response = client.postForObject("http://localhost:8080/postuser", paramMap, String.class);
    System.out.println(response);
}

③使用postForexchange

@Test
public void postForexchange() {
    // 封装参数,千万不要替换为Map与HashMap,否则参数无法传递
    MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
    paramMap.add("name", "longzhonghua");
    paramMap.add("id", 4);
    RestTemplate client = restTemplateBuilder.build();
    HttpHeaders headers = new HttpHeaders();
    //headers.set("id", "long");
    HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String, Object>>		(paramMap,headers);
    ResponseEntity<String> response = client.exchange("http://localhost:8080/postuser", 						HttpMethod.POST,httpEntity,String.class,paramMap);
    System.out.println(response.getBody());
}

④使用postForLocation

​ 它用于提交数据,并获取返回的URI。一般登录注册都是POST请求,操作完成之后,跳转到某个页面,这种场景就可以使用postForLocation。所以,先要添加处理登录的API:

@ResponseBody
    @RequestMapping(path = "success")
    public String loginSuccess(String name, Integer id) {
        return "welcome " + name;
    }

    @RequestMapping(value = "/post", method = RequestMethod.POST)
    public String post(HttpServletRequest request, @RequestParam(value = "name", required = false) String name,
                       @RequestParam(value = "password", required = false) String password, @RequestParam(value = "id", required = false) Integer id, HttpServletResponse response) {
       // 如果获取的值为“null”,则需要把URI添加到response信息的header中。添加方法为:“response.addHeader("Location",uri)”
        response.addHeader("Location", "success?name=" + name + "&id=" + id + "&status=success");
        return "redirect:/success?name=" + name + "&id=" + id + "&status=success";
        // return "redirect:/success?name=" + URLEncoder.encode(name, "UTF-8") + "&id=" + id + "&status=success";

    }

然后使用postForLocation请求

@Test
    public void postForLocation() {
        // 封装参数,千万不要替换为Map与HashMap,否则参数无法传递
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<String, Object>();
        paramMap.add("name", "longzhonghua");
        paramMap.add("id", 4);

        RestTemplate client = restTemplateBuilder.build();

        URI response = client.postForLocation("http://localhost:8080/post",paramMap);

         System.out.println(response);
    }
posted @ 2021-10-04 10:30  DarkerG  阅读(147)  评论(0编辑  收藏  举报