Spring Boot 构建⼀一个 RESTful Web 服务 -2019-08-18

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平行的目录

  1. 测试创建消息(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"}

代表创建成功

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,695评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,569评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,130评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,648评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,655评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,268评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,835评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,740评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,286评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,375评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,505评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,873评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,357评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,466评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,921评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,515评论 2 359