ResponseEntity

  • 简介:继承自HttPEntity类,封装了请求后返回的响应头、响应体和响应状态。
  • 作用:用于controller层向前端返回数据和状态码。
  • 构造器:
  • new ResponseEntity(HttpStatus.OK): http状态码。
  • new ResponseEntity(new User(),HttpStatus.OK): 泛型对象的数据和http状态码。
  • new ResponseEntity(MultiValueMap<String, String> headers, HttpStatus statusCode):http首部(如,HttpHeaders类)和状态码。
  • new ResponseEntity(new User(), MultiValueMap<String, String> headers, HttpStatus statusCode)
  • 示例:
@RequestMapping(value="/response/entity/status", method=RequestMethod.GET)   
public ResponseEntity<String> responseEntityStatusCode() {  

    return new ResponseEntity<String>("The String ResponseBody with 
        custom status code (403 Forbidden)",   
        HttpStatus.FORBIDDEN);   
}
  • 以上方法相当于以下@ResponseBody+@ResponseStatus,它会返回@RequestMapping原页面,显示字符串,并带回一个状态码:
@RequestMapping(value="/response/entity/status", method=RequestMethod.GET)   
@ResponseStatus(HttpStatus.FORBIDDEN)
public String responseEntityStatusCode() {  

    return "The String ResponseBody with 
        custom status code (403 Forbidden)",   
}
  • 虽然这里将状态码设为HttpStatus.FORBIDDEN,但是字符串仍能正常显示在页面上,那么HttpStatus.FORBIDDEN起什么作用呢?
  • 我们配合RestTemplate写个例子,对该url发起访问,运行结果显示,发起请求失败,后台抛出402异常,但前端照常显示字符串:
public static void main(String[] args) {  
    RestTemplate template = new RestTemplate();  
    //调用getForEntity抛出异常
    ResponseEntity<String> entity = template.getForEntity(  
            "http://localhost:8080/web/response/entity/status", String.class);  
    String body = entity.getBody();  
    MediaType contentType = entity.getHeaders().getContentType();  
    HttpStatus statusCode = entity.getStatusCode();  
    System.out.println("statusCode:[" + statusCode + "]");  
}
  • 异常日志:
Exception in thread "main" org.springframework.web.client.HttpClientErrorException: 403 Forbidden
    at org.springframework.web.client.DefaultResponseErrorHandler
        .handleError(DefaultResponseErrorHandler.java:76)
    at org.springframework.web.client.RestTemplate.handleResponseError(
        RestTemplate.java:486)
    at org.springframework.web.client.RestTemplate.doExecute(
        RestTemplate.java:443)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
    at org.springframework.web.client.RestTemplate.getForEntity(
        RestTemplate.java:221)
    at org.springframework.samples.mvc.response.ResponseControllerTest.main(
        ResponseControllerTest.java:12)
  • 回到ResponseEntity构造器的测试,以下代码进一步指定返回内容的content-type为text/plain。
@RequestMapping(value="/response/entity/headers", method=RequestMethod.GET)  
public ResponseEntity<String> responseEntityCustomHeaders() {  

    HttpHeaders headers = new HttpHeaders();  
    headers.setContentType(MediaType.TEXT_PLAIN);  
    return new ResponseEntity<String>("The String ResponseBody with 
        custom header Content-Type=text/plain",  
        headers, //指定content-type
        HttpStatus.OK);  
}
  • 参考文章
  • 代码示例:ideaProjects/shiro-cahpter17/web/AuthorizeController

RestTemplate

  • Spring提供的用于访问Rest服务器的客户端。通常用于模拟请求,分析返回的响应数据。
  • 方法:
  • getForEntity():发送get请求,返回ResponseEntity类,包含了响应体所映射成的对象,比如,响应体数据为一个由User转化的json,那么它被封装进ResponseEntity时将转回User对象。我们用一个ResponseEntity对象接收该方法返回值后,可取出其中的响应体对象、响应头和响应状态。
  • getForObject():同上,不过只返回User对象。
  • postForEntity():post请求。
  • postForObject():post请求。
  • delete():在特定的URL上对资源执行HTTP DELETE操作。
  • exchange():在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity,这个对象是从响应体中映射得到的。
  • execute():在URL上执行特定的HTTP方法,返回一个从响应体映射得到的对象。
  • headForHeaders():发送HTTP HEAD请求,返回包含特定资源URL的HTTP头。
  • optionsForAllow():发送HTTP OPTIONS请求,返回对特定URL的Allow头信息。
  • postForLocation():POST 数据到一个URL,返回新创建资源的URL。
  • put():PUT 资源到特定的URL。
getForEntity()
  • getForEntity(String url,Class responseType,Map<String,?> uriVariables/Object… uriVariables):目标url,响应体映射的对象,url参数(0个或多个)。
/**
 * 将要被请求的controller
 **/
@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping(value = "getAll")
    public List<UserEntity> getUser() {
        List<UserEntity> list = userService.getAll();
        return list;
    }
}

/**
 * 模拟请求的controller
 **/
@RestController
public class UserController {
    @RequestMapping("getForEntity")
    public List<UserEntity> getAll2() {
        //模拟请求并获取响应数据
        ResponseEntity<List> responseEntity = 
            restTemplate.getForEntity("http://localhost/getAll", List.class);
        //获取响应头
        HttpHeaders headers = responseEntity.getHeaders();
        //响应状态
        HttpStatus statusCode = responseEntity.getStatusCode();
        int code = statusCode.value();
        //响应体
        List<UserEntity> list = responseEntity.getBody();

        System.out.println(list.toString());
        return list;
    }
}
  • 有参数的getForEntity(),可以使用{}先在url中占位,然后在方法最后一位参数补上此url参数:
//待请求的controller类中
@RequestMapping("get/{id}")
public UserEntity getById(@PathVariable(name = "id") String id) {
    return userService.getById(id);
}

//模拟请求的controller
@RequestMapping("getForEntity/{id}")
public UserEntity getById2(@PathVariable(name = "id") String id) {
    //模拟带参数的get请求
    ResponseEntity<UserEntity> responseEntity = restTemplate.getForEntity(
        "http://localhost/get/{id}", UserEntity.class, id); //Object...形式的参数
    /*也可采用Map形式的参数
    * HashMap<String, String> map = new HashMap<>();
    * map.put("id",id);
    * ResponseEntity<UserEntity> responseEntity = restTemplate.getForEntity(
    *     "http://localhost/get/{id}", UserEntity.class, map);
    */

    UserEntity userEntity = responseEntity.getBody();
    return userEntity;
}
  • getForEntity(URI uri,Class responseType): 不做测试了。
getForObject()
  • 有的时候不需要全部的响应数据,只要响应体就足够了。
  • getForObject(URI uri,Class responseType)。
  • getForObject(String url.Class responseType,Map<String,?>/Object… uriVariables):
//无参数的 getForObject 请求
@RequestMapping("getAll2")
public List<UserEntity> getAll() {
    List<UserEntity> list = restTemplate.getForObject("http://localhost/getAll", 
                                                      List.class);

    System.out.println(list.toString());
    return list;
}

//有参数的 getForObject 请求
@RequestMapping("get2/{id}")
public UserEntity getById(@PathVariable(name = "id") String id) {
    //使用Object...形式的参数
    UserEntity userEntity = restTemplate.getForObject(
        "http://localhost/get/{id}", UserEntity.class, id);
    /*也可使用Map形式
    * HashMap<String, String> map = new HashMap<>();
    * map.put("id",id);
    * UserEntity userEntity = * restTemplate.getForObject(
    *       "http://localhost/get/{id}", UserEntity.class, map);
    */

    return userEntity;
}
postForEntity()
  • postForEntity(String url,Object request,Class responseType,Map<String,?>/Object… uriVariables): url,request:要放在post报体中的参数;响应体映射的实体,url参数。
@RequestMapping(value = "save")
public String save(UserEntity userEntity) {
    return "保存成功";
}

//post 请求,提交 UserEntity 对象
@RequestMapping("saveUser")
public String save(UserEntity userEntity) {
    ResponseEntity<String> responseEntity = restTemplate.postForEntity(
        "http://localhost/save", userEntity, String.class);
    String body = responseEntity.getBody();

    return body;
}
  • 浏览器访问http://localhost/saveUser?username=itguang&password=123456&age=20&email=123@123.com,后面参数将被自动封装到UserEntity中传入方法。提交的数据和请求后返回的ResponseEntity如下:





  • 有参数的postForEntity():
@RequestMapping(value = "saveByType/{type}") //type实际并非参数,而是url的一部分
public String saveByType(UserEntity userEntity,
     @PathVariable("type")String type) { //但是它要作为参数传给方法使用
    return "保存成功,type="+type;
}

@RequestMapping("saveUserByType/{type}")
public String save2(UserEntity userEntity,@PathVariable("type")String type) {

    //使用Object...形式传参,也可使用Map
    ResponseEntity<String> responseEntity = restTemplate.postForEntity(
        "http://localhost/saveByType/{type}", userEntity, String.class, type);

    String body = responseEntity.getBody();
    return body;
}
  • 浏览器访问localhost/saveUserByType/120?username=itguang&password=123456&age=20&email=123@123.com,返回:保存成功,type=120.
  • 参考文章

HttpStatus.FORBIDDEN起什么作用呢

  • 前面ResponseEntity第一个例子将状态码设为HttpStatus.FORBIDDEN,但是字符串仍能正常显示在页面上,那么HttpStatus.FORBIDDEN起什么作用呢?
  • 我们配合RestTemplate写个例子,对该url发起访问,运行结果显示,发起请求失败,后台抛出402异常,但前端照常显示字符串:
public static void main(String[] args) {  
    RestTemplate template = new RestTemplate();  
    //调用getForEntity抛出异常
    ResponseEntity<String> entity = template.getForEntity(  
            "http://localhost:8080/web/response/entity/status", String.class);  
    String body = entity.getBody();  
    MediaType contentType = entity.getHeaders().getContentType();  
    HttpStatus statusCode = entity.getStatusCode();  
    System.out.println("statusCode:[" + statusCode + "]");  
}
  • 异常日志:
Exception in thread "main" org.springframework.web.client.HttpClientErrorException: 403 Forbidden
    at org.springframework.web.client.DefaultResponseErrorHandler
        .handleError(DefaultResponseErrorHandler.java:76)
    at org.springframework.web.client.RestTemplate.handleResponseError(
        RestTemplate.java:486)
    at org.springframework.web.client.RestTemplate.doExecute(
        RestTemplate.java:443)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
    at org.springframework.web.client.RestTemplate.getForEntity(
        RestTemplate.java:221)
    at org.springframework.samples.mvc.response.ResponseControllerTest.main(
        ResponseControllerTest.java:12)