您的位置:首页 > 编程语言 > Java开发

Spring 初探(十)(Spring RESTful web 应用)

2017-01-01 13:12 295 查看
Spring RESTful web的一个简单应用场景如 在网络应用中对数据库对象进行

有关增删改查的工作 如对于关注的对象的存取及删除都是可以进行的。

下面的部分使用了Spring 初探(九)的示例代码 搭建Spring RESTful web 的简单示例应用

先对一些基本概念进行

简要介绍。

HTTP具有如下方法来操作数据交互:

GET 不在request中设定body而返回body

DELETE remove URI做指定的资源

PUT update URI所指定的资源 使用需要发送GET所得到的类似结果

POST add or append URI所指定的资源 也可能被类似PUT的方法对待
下面来看一个示例部分代码:

Ex:

package bookmarks;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.http.ResponseEntity;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.net.URI;
import java.util.Collection;

/**
* Created by ehang on 2016/12/31.
*/

@RestController
@RequestMapping("/{userId}/bookmarks")
class BookmarkRestController {
private final BookmarkRepository bookmarkRepository;
private final AccountRepository accountRepository;

@Autowired
BookmarkRestController(BookmarkRepository bookmarkRepository, AccountRepository accountRepository)
{
this.bookmarkRepository = bookmarkRepository;
this.accountRepository = accountRepository;
}

@RequestMapping(method = RequestMethod.GET)
Collection<Bookmark> readBookMarks(@PathVariable String userId)
{
this.validateUser(userId);
return this.bookmarkRepository.findByAccountUsername(userId);
}

@RequestMapping(method = RequestMethod.POST)
ResponseEntity<?> add(@PathVariable String userId, @RequestBody Bookmark input){
return this.accountRepository.findByUsername(userId).map(
account -> {
Bookmark result = bookmarkRepository.save(new Bookmark(account, input.uri, input.description));
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(result.getId()).toUri();
return ResponseEntity.created(location).build();
}

).orElse(ResponseEntity.noContent().build());
}

@RequestMapping(method = RequestMethod.GET, value = "/{bookmarkId}")
Bookmark readBookmark(@PathVariable String userId, @PathVariable Long bookmarkId)
{
this.validateUser(userId);
return this.bookmarkRepository.findOne(bookmarkId);
}

private void validateUser(String userId){
this.accountRepository.findByUsername(userId).orElseThrow(() -> new UserNotFoundException(userId));
}

}


package bookmarks;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

/**
* Created by ehang on 2016/12/31.
*/
@ResponseStatus(HttpStatus.NOT_FOUND)
class UserNotFoundException extends  RuntimeException{
public  UserNotFoundException(String userId)
{
super("could not find user '" + userId + "'.");
}

}


下面是对上述部分的解释:

@RestController = @Controller + @ResponseBody

@Controller

 声明作为接受HttpServletRequest及HttpServletResponse的HttpServlet(服务端

 更新修改数据)

@ResponseBody

 本来是用来修饰method 声明其返回值被response body所包括,

 在Spring 4开始也可以修饰类这一层次 指定方法具备上述行为。

@RequestBody

 用来修饰method的参数表示request body

 声明后的body将由HttpMessageConverter根据context type进行“解释”
这里@Autowired作用于构造函数(对参数实现自动链接)

这里validateUser函数中调用了Spring初探(九)中提到的Optional类

的orElseThrow方法,其支持使用lambda表达式抛出异常的形式,

其他相关方法的介绍可参看:
http://www.importnew.com/6675.html
由@RequestMapping("/{userId}/bookmarks")及@PathVariable String userId

共同指定了传入uri的userid部分作为String类型形参传入
ResponseEntity是response的包装者(wrapper)

其基本包含response headers 及status code
JpaRepository使用save方法(接受单个entity 或容器作为参数)

ServletUriComponentsBuilder

从HttpServletRequest中抽出information的UriComponentsBuilder

其定义了诸from开头的方法都是返回特定的(需要的)ServletUriComponentsBuilder

的工厂函数。

这里所用到的 fromCurrentRequest在除了request是由RequestContextHolder得到

的情况外是与fromRequest相同的,后者是返回拷贝了诸url部分(scheme host port path

query string)Builder

RequestContextHolder

可以通过RequestAttribute对象来展示request的holder 当相应的继承属性被设置为true后

这个request可以被此线程生成的子线程继承

(相应的继承方法可以通过设定setRequestAttributes方法的参数完成)
fromCurrentRequest与fromRequest的区别可以通过如下例子看到,

来源于:
https://github.com/spring-projects/spring-framework/blob/master/spring-webmvc/src/test/java/org/springframework/web/servlet/support/ServletUriComponentsBuilderTests.java
Spring test源码:

Ex:

@Test

public void fromRequest() {

this.request.setRequestURI("/mvc-showcase/data/param");

this.request.setQueryString("foo=123");

String result = ServletUriComponentsBuilder.fromRequest(this.request).build().toUriString();

assertEquals("http://localhost/mvc-showcase/data/param?foo=123", result);

}

@Test

public void fromCurrentRequest() {

this.request.setRequestURI("/mvc-showcase/data/param");

this.request.setQueryString("foo=123");

RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(this.request));

try {

String result = ServletUriComponentsBuilder.fromCurrentRequest().build().toUriString();

assertEquals("http://localhost/mvc-showcase/data/param?foo=123", result);

}

finally {

RequestContextHolder.resetRequestAttributes();//resetRequestAttributes() 就是setRequestAttributes(null)

}

}


UriComponentsBuilder path(String path)

在此Builder有的 path后面append path

buildAndExpand

组成UriComponents实例 replace URI template variables("/{id}") from array(result.getId())
add函数的orElse部分使用noContent()指定HttpStatus 204 no content

整个函数构建过程可以概括为使用生成URI -> create location(URI)

JPA findOne使用外键@Id寻找对象。

关于代码的解释已经比较细致了,如果还想进一步看细节可参看原文: https://spring.io/guides/tutorials/bookmarks/
有关将上述示例表述为HAL形式的介绍可参看Spring 初探(十二)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java Spring RESTful POST GET