Spring MVC REST风格

在REST风格中,每一个资源都只是对应一个网址,而一个代表资源的网址应该是一个名词,而不存在动词。比如:获取id为1的用户URL可以设计为:http://localhost:8080/user/1。

1.名称解释

REST Representational State Transfer

  • Representational 资源:这可以是系统权限用户、角色和菜单,也可以是一些媒体类型的,如文本、图片、歌曲
  • Transfer 表示层: 有了资源还需要确定如何表示这个资源。
  • State 状态转换:现在中资源不是一成不变的,它是一个变化的过程,一个资源可以经历创建(create)、访问(visit)、修改(update)、和删除(delete)。

REST风格架构特点:

  • 服务器存在一系列资源,每个资源通过单独唯一URI进行标识
  • 客户端和服务器之间可以相互传递资源,而资源会以表现层得以展示
  • 客户端通过HTTP协议所定义的运作对资源进行操作

2.HTTP动作

REST对应HTTP5种动作

  • GET(VISIT):访问服务器资源
  • POST(CREATE):提交服务器资源信息,用来创建新资源
  • PUT(UPDATE):修改服务器资源信息。需要把所有属性一并提交
  • PATCH(UPDATE):修改服务器已经存在的资源,可以部分资源属性提交。(有些Java类不能完全支持)
  • DELETE:从服务器将资源删除
    两个不常用的动作午觉
  • HEAD:获取资源元数据(Content-type)
  • OPTIONS:提供资源可以客户端修改的属性信息

URI设计:

GET /user/1
GET /users/{userName}/{note}
POST /user/{userName}/{note}
PUT /user/{id}/{userName}/{sex}/{note}
PATCH /user/{id}{userName}

3 使用Spring开发Rest风格

假设已经开发好了服务层(Service)和数据访问层(DAO),那么只需要开发控制器就可以了。对于DAO层而言,使用的是PO(Persistent Object),它直接对应数据库表。

POJO:


@Alias("user")
public class User {
    private Long id ;
    private String userName;
    private SexEnum sexEnum = null;
    private String note;

 --- getter setter
}

对于PO,它的属性sex是一个枚举SexEnum类型,这会让前端难以理解。为了处理它,需要一个VO(View Object,视图对象)去转换

VO:


public class UserVo {
    private Long id;
    private String userName;
    private int sexCode;
    private String sexName;
    private String note;
    
    --- getter setter 
}

简单使用案例:


@Controller
@RequestMapping
public class UserController {

    @Autowired
    private UserService userService = null;


    // 转换 V0变为PO
    private User changeToPo(UserVo userVo) {
        User user = new User();
        user.setId(userVo.getId());
        user.setUserName(userVo.getUserName());
        user.setSexEnum(SexEnum.getSexEnum(userVo.getSexCode()));
        user.setNote(userVo.getNote());
        return  user;
    }

    // 转换PO变为VO
    private UserVo changeToVo(User user) {
        UserVo userVo = new UserVo();
        userVo.setId(user.getId());
        userVo.setUserName(user.getUserName());
        userVo.setSexCode(user.getSexEnum().getCode());
        userVo.setSexName(user.getSexEnum().getName());
        userVo.setNote(user.getNote());
        return userVo;
    }

    // PO列表转为VO列表
    private List<UserVo> changeToVoes(List<User> poList){
        List<UserVo> voList = new ArrayList<>();
        for(User user: poList){
            UserVo userVo = changeToVo(user);
            voList.add(userVo);
        }
        return voList;
    }

    @GetMapping
    @ResponseBody
    public List<UserVo> findUsers(
            @PathVariable("userName") String userName,
            @PathVariable("note") String note,
            @PathVariable("start") int start,
            @PathVariable("limit") int limit){
        List<User> userList = userService.findUsers(userName,note,start,limit);
        return this.changeToVoes(userList);
    }

4 使用 @RestController

现在前后端分离,使用JSON交互很普遍。如果第一个方式都加@ResponseBoby才能将数据转换为JSON,这有些冗余。Rest风格中,存在@RestController,相当于 @Controller+@ResponseBoby

@RestController
@RequestMapping
public class UserController { ...}

5 使用RestTemplate

获取用户:

  public static UserVo getUser(Long id) {
        RestTemplate restTemplate = new RestTemplate();
        UserVo userVo = restTemplate.getForObject(
                "http://localhost:/8080/user/{id}", UserVo.class, id
        );
        System.out.println(userVo.getUserName());
        return userVo;
    }
    

getForObject

  • 第一个参数 URI 标明请求服务器什么资源,{id } 代表参数
  • UserVo.class 表示请求将返回UserVo类的结果,服务器只会返回JSON类型的数据,RestTemplate内部会将其转变成Java对象
  • 第二个参数后面,则是URI对应的参数,它是一个可变长的参数。

RestTemplate 多个参数的用法


public static List<UserVo> findUser(String userName,
                            String note, int start, int limit) {
        RestTemplate restTemplate = new RestTemplate();
        Map<String, Object> params = new HashMap<>();
        params.put("userName", "user");
        params.put("note", "note");
        params.put("start", start);
        params.put("limit", limit);
        // Map 中的key和URI中的参数一一对应
        String url = "http://localhost:/8080/users/{userName}/{note}/{start}/{limit}";
        // 请求后端
        ResponseEntity<List> responseEntity = restTemplate.getForEntity(url, List.class, params);
        List<UserVo> userVos = responseEntity.getBody();
        return userVos;
    }

可以将参数用Map对象封装起来,Map的键和URI中所定义的参数是保持一致的。

新增用户的场景,新增用户时字段较多,往往会采用传递的请求体(Body)的方式 。

POST请求传递JSON请求体:

public static User insertUser(UserVo newUserVo) {
    HttpHeaders headers = new HttpHeaders();
    // 设置请求内容为JSON类型
    headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
    // 创建请求实体对象
    HttpEntity<UserVo> request = new HttpEntity<>(newUserVo, headers);
    RestTemplate restTempl = new RestTemplate();
    // 请求时传递请求实体的对象,并返回回填id的用户
    User user = restTempl.postForObject("http://localhost:8080/user", request, User.class);
    System.out.println(user.getId());
    return user;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值