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

来源:互联网 发布:windows update是什么 编辑:程序博客网 时间:2024/05/24 05:34

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:

@Testpublic 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);}@Testpublic 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 初探(十二)


0 0