Spring Boot 对 RESTful 的⽀支持
Spring Boot 全⾯面⽀支持开发 RESTful 程序,通过不不同的注解来⽀支持前端的请求,除了经常使⽤的注解外, Spring Boot 还提了一些组合注解。这些注解来帮助简化常用的 HTTP ⽅方法的映射,并更更好地表达被注解⽅法的语义。
- @GetMapping,处理 Get 请求
- @PostMapping,处理 Post 请求
- @PutMapping,⽤于更新资源
- @DeleteMapping,处理删除请求
- @PatchMapping,⽤于更新部分资源
这些组合的注解就是@RequestMapping 的简写版本,通常来讲会映射到RequestMethod的某个具体的方法。
@GetMapping(value="/xxx")
等价于
@RequestMapping(value = "/xxx",method = RequestMethod.GET)
@PostMapping(value="/xxx")
等价于
@RequestMapping(value = "/xxx",method = RequestMethod.POST)
@PutMapping(value="/xxx")
等价于
@RequestMapping(value = "/xxx",method = RequestMethod.PUT)
@DeleteMapping(value="/xxx")
等价于
@RequestMapping(value = "/xxx",method = RequestMethod.DELETE)
@PatchMapping(value="/xxx")
等价于
@RequestMapping(value = "/xxx",method = RequestMethod.PATC
通过以上可以看出 RESTful 在请求的类型中就指定了了对资源的操控。
按照RESTful的思想我们设计一组对用户的操作
请求 | 地址 | 说明 |
---|---|---|
get | /messages | 获取所有消息 |
post | /message | 创建⼀一个消息 |
put | /message | 修改消息内容 |
patch | /message/text | 修改消息的 text 字段 |
get | /message/id | 根据 ID 获取消息 |
delete | /message/id | 根据 ID 删除消息 |
put ⽅方法主要是⽤用来更更新整个资源的,⽽而 patch ⽅方法主要表示更更新部分字段。
开发步骤
定义一个Message 类
public class Message {
private Long id;
private String text;
private String summary;
}
Message对象的增删查改操作
我们使用ConcurrentHashMap来存储Message对象的增删查改,用AtomicLong来作为消息的自增组件使用。ConcurrentHashMap 是 Java 中⾼高性能并发的 Map 接⼝口,AtomicLong 作⽤用是对⻓长整形进⾏行行原⼦子操 作,可以在⾼高并场景下获取到唯⼀一的 Long 值。
@Service("messageRespository")
public class InMemoryMessageRespository implements MessageRespository {
private static AtomicLong counter = new AtomicLong();
private final ConcurrentMap<Long, Message> messages = new ConcurrentHashMap<>( );
}
查询所有用户的方法
@Override
public List<Message> findAll() {
List<Message> messages = new ArrayList<Message>(this.messages.values());
return messages;
}
消息Id的获取和创建
保持消息时,需要判断Id是否存在,如果不存在用AtomicLong创建一个
@Override
public Message save(Message message) {
Long id = message.getId();
if (id == null) {
id = counter.incrementAndGet();
message.saveId(id)
}
this.mesage.put(id,message);
return message;
}
更新时直接覆盖对应的key
@Override
public Message update(Message message) {
this.message.put(message.getId(),message);
return message;
}
更更新 text 字段:
@Override
public Message updateText(Message message) {
Message msg=this.messages.get(message.getId());
msg.setText(message.getText());
this.messages.put(msg.getId(), msg);
return msg;
}
封装根据 ID 查找和删除消息
@Override
public Message findMessage(Long id) {
return this.messages.get(id);
}
@Override
public void deleteMessage(Long id) {
this.messages.remove(id);
}
封装 RESTful 的处理理
将上⾯面封装好的 MessageRepository 注⼊入到 Controller 中,调⽤用对应的增删改查⽅方法。
@RestController
@RequestMapping("/")
public class MessageController {
@Autowired
private MessageRepository messageRepository;
// 获取所有消息体
@GetMapping(value = "messages") public List<Message> list() {
List<Message> messages = this.messageRepository.findAll();
return messages;
}
// 创建⼀一个消息体
@PostMapping(value = "message")
public Message create(Message message) {
message = this.messageRepository.save(message);
return message;
}
// 使⽤用 put 请求进⾏行行修改
@PutMapping(value = "message")
public Message modify(Message message) {
Message messageResult=this.messageRepository.update(message);
return messageResult;
}
// 更更新消息的 text 字段
@PatchMapping(value="/message/text") public Message patch(Message message) {
Message messageResult=this.messageRepository.updateText(message);
return messageResult;
}
@GetMapping(value = "message/{id}")
public Message get(@PathVariable Long id) {
Message message = this.messageRepository.findMessage(id);
return message;
}
@DeleteMapping(value = "message/{id}")
public void delete(@PathVariable("id") Long id) {
this.messageRepository.deleteMessage(id);
}
}
进行测试
我们使用 MockMvc 进⾏测试。MockMvc 实现了对 Http 请求的模拟,能够直接使⽤网络的形式,转换到 Controller 的调⽤,这样可以使得测试速度快、不不依赖⽹网络环境,⽽而且提供了一套验证的工具,这样可以使得 请求的验证统⼀而且很⽅方便。
MockMvc的架构如下
@RunWith(SpringRunner.class)
@SpringBootTest
public class MessageControllerTest {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
}
- @SpringBootTest 注解是 SpringBoot 自 1.4.0 版本开始引⼊的一个用于测试的注解
- @RunWith(SpringRunner.class) 代表运行⼀个 Spring 容器
- @Before 代表在测试启动时候需要提前加载的内容,这⾥是提前加载 MVC 环境
MessageControllerTest 应该在整个项目代码的最外层目录,也就是跟RestfulApplication平行的目录
- 测试创建消息(post 请求)
@Test
public void saveMessage() throws Exception {
final MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("text", "text");
params.add("summary", "summary");
String mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/message")
.params(params)).andReturn().getResponse().getContentAsString();
System.out.println("Result === " + mvcResult);
}
}
运行之后如果显示
Result === {"id":1,"text":"text","summary":"summary","created":"2019-09-06T03:45:27.625+0000"}
代表创建成功