spring-boot-learning-REST风格网站

什么是REST风格:

Representational State Transfer :表现层状态转换,实际上是一种风格。标准,约定

首先需要有资源才能表现, 所以第一个名词是“ 资源”。有了资源也要根
据需要以合适的形式表现资源,这就是第二个名词一一表现层。最后是资源可以被新增、修改、删
除等,也就是第三个名词“状态转换”。

资源: 它可以是系统权限用户、角色和菜单等,也可以是一些媒体类型, 如文本、图片、歌曲,总之它就是一个具体存在的
对象。可以用一个URI ( Unifonn Resource Identifier ,统一资源定位符)指向它, 每个资源对应一个特定的U阳。
要获取这个资源, 访问它的U阳即可,而在REST 中每一个资源都会对应一个独一无二的U阻。在阻ST 中, URI 也可以称
为端点(End Point ) 。

 

表现层: 有了资源还需要确定如何表现这个资源。例如, 一个用户可以使用JSON 、XML 或者其他的形式表现出来,又如
可能返回的是一幅图片。在现今的互联网开发中, JSON 数据集己经是一种最常用的表现形式

 

 

REST风格当中,每一个资源都只是对应一个网址,而一个资源网址应该是一个名词,不存在动词。

 

 

URI (Unifonn Resource Identifier)统一资源定位符

 

 

REST风格其实就是一种约定问题,不同的http请求对应的不同的资源操作,

 

@GetMapping

 

/**
 * RestController,作用是使返回的结果能够以json数据集的方法进行返回
 * 转换为JSTL或者json
 * 11默认将方法或者类标注为application/json;charset=UTF-8
 * 22方法执行结束后,spring会遍历注册号的HttpMessageConverter接口
 * 的实现类。
 * 33注册好的MappingJackson2HttpMessageConverter就会放回true,
 *      启动转换器将结果转换为JSON数据集
 */
@RestController
@RequestMapping("annotation")
public class RedisUserController {
    @Autowired
    private UserService userService =null;

    /**
     * http的get请求,获取资源
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public User getUser(@PathVariable("id") Long id){
        System.out.println(System.currentTimeMillis());
        User user = userService.getUser(id);
        System.out.println(System.currentTimeMillis());
        return user;
    }

请求:

 

 

@PostMapping

   /**
     * http的post请求,创建资源
     * @param userName
     * @param note
     * @return
     */
    @PostMapping()
    public User insertUser(
            @RequestParam ("userName") String userName,
            @RequestParam ("note") String note
    ){
        User user = new User();
        user.setUserName(userName);
        user.setNote(note);
        userService.insertUser(user);
        return user;
    }

 

请求结果;

 

 

@DeleteMapping

 /**
     * http的Delete请求,删除服务器资源
     * @param id
     * @return
     */
    @DeleteMapping("{id}")
    public int delUser(@PathVariable("id") Long id){
        return userService.deleteUser(id);
    }

 

 

从数据库中删除了id为44员工

 

@PutMapping

@PatchMapping

  /**
     * http Put请求,提交所有的资源属性以修改资源,
     * http patch请求,提交资源的部分修改属性,
     * 其实他们两个都差不多,只不过是约定的问题而已
     * @param id
     * @param userName
     * @return
     */
    @PatchMapping("/user/{id}")
    public User updUser(
            @PathVariable("id") Long id,
            @RequestParam("userName") String userName
    ){
       return userService.updateUser(id,userName);
    }

修改之前的:

 

 

 

 

 

处理HTTP请求状态码,异常和响应头

 

通过实体类去实现;

/**
 * 当发生资源找不到或者处理逻辑发生异常时,需要考虑返回给客户端的http状态码和错误消息
 * spring提供实体封装类ResponseEntity:有效的封装错误消息和状态码
 * 和注解@ResponseStatus:配置指定的响应码给客户端
 */
@RestController
public class HttpStatusController {
    @Autowired
    UserService userService;


    /**
     * 11新建一个请求头对象,
     * 22向请求头通过add方法进行加入k-v
     * 33需要建立一个响应实体类,将需要放回的信息,请求头对象,响应http状态码
     * 备注:这里使用 HttpStatus.CREATED ,指定状态码为201,标识资源创建成功
     * @param userName
     * @param note
     * @return
     */
    @PostMapping("/http/status")
    public ResponseEntity<Integer> insertUser(
            @RequestParam("userName") String userName,
            @RequestParam ("note") String note
    ){
        User user = new User();
        user.setUserName(userName);
        user.setNote(note);
        Integer re = userService.insertUser(user);
//        设置http响应头
        HttpHeaders httpHeaders = new HttpHeaders();//新建请求头
        String success = (re == 0 ) ? "false" : "true";//如果结果为0,就是false
        httpHeaders.add("success",success);


        return new ResponseEntity<Integer>(re,httpHeaders, HttpStatus.CREATED);
    }

 

 

 

 

使用注解: 

  /**
     * 通过注解@ResponseStatus去指定
     * 当方法正常返回的时候,http状态码为201
     * @param userName
     * @param note
     * @return
     */
    @PostMapping("/http/status/an")
    @ResponseStatus(HttpStatus.CREATED)
    public Integer insertUseran(
            @RequestParam("userName") String userName,
            @RequestParam ("note") String note
    ){
        User user = new User();
        user.setUserName(userName);
        user.setNote(note);
        Integer re = userService.insertUser(user);

        return  re;
    }
}

 

 

异常处理;

 

定义一个运行时的异常:

//场景:运行的时候,查询id用户,找不到数据或出现异常,这时候不能以正常返回去处理。
/**
 * 11自定义异常类:找不到用户的时候抛出异常
 * 异常抛出后,可以在控制器通知@ControllerAdvice里面进行处理
 * @ControllerAdvice:定义控制器通知
 * @ExceptionHandler:指定异常发生的处理方法
 *继承的异常RuntimeException是指:运行时的异常,和我们普通的
 * Exception:受检查的异常,这种异常是强制我们catch或throw的异常。
 *    你遇到这种异常必须进行catch或throw,如果不处理,编译器会报错。
 *
 */
public class NotFoundException extends RuntimeException{
    public static final long serialVersionUID = 1L;

    private Long code;//异常编码
    private String customMsg;//异常自定义消息

    public NotFoundException() {
    }

    public NotFoundException(Long code, String customMsg) {
        super();
        this.code = code;
        this.customMsg = customMsg;
    }

    public Long getCode() {
        return code;
    }

    public void setCode(Long code) {
        this.code = code;
    }

    public String getCustomMsg() {
        return customMsg;
    }

    public void setCustomMsg(String customMsg) {
        this.customMsg = customMsg;
    }
}

 

定义一个控制器通知:

/**
 * 2自定义一个控制器通知
 *      在@ControllerAdvice中指定拦截包路径,限定被拦截的注解为@Controller/@RestController
 *      在@ExceptionHandler注解方法上,通过value属性,指定异常类型进行拦截
 *      在@ResponseBody定义响应的信息已json的格式表达
 *      在@ResponseStatus定义服务器内部错误500代码
 */
@ControllerAdvice(
        basePackages = {"com.quan.annotationredis.controller.*"},
        annotations = {Controller.class, RestController.class}
)
public class UserControllerAdvice {
    @ExceptionHandler(value = NotFoundException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)//定义服务器错误代码
    @ResponseBody
    public Map<String,Object> exception(HttpServletRequest request,
                                        NotFoundException ex){
        Map<String,Object> msgMap = new HashMap<>();
        msgMap.put("code",ex.getCode());
        msgMap.put("message",ex.getCustomMsg());
        return msgMap;
    }
}

 

测试controller:

@Controller
public class ExceptionController {

    @Autowired
    UserService userService;

    /**
     * 一旦方法出现异常,就会别控制器通知所拦截,最后经@ExceptionHandler定义
     * 的方法进行处理。
     * @param id
     * @return
     */
    @GetMapping("/exception/{id}")
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public User getUser(@PathVariable("id") Long id){
        System.out.println(System.currentTimeMillis());
        User user = userService.getUser(id);
        if (user == null){
            throw new NotFoundException(1L,"找不到用户"+id+"的信息");
        }
        System.out.println(System.currentTimeMillis());
        return user;
    }
}

 

 

 

 

 

使用RestTemplate请求后端;

底层是通过类HttpURLConnection实现的。

 

    /**
     * restTemplate.getForObject方法中:
     * 第一个参数URL:标明请求服务器什么资源,{id}代表参数
     * 第二个参数:表示将请求返回User类的结果,实际上服务器只会给回我们json格式数据
     *          是因为restTemplate内部将其转化给java对象。
     *  第三个参数:就是URL对应的参数。
     * @return
     */
    private static  User getUser() {
        int id = 1;
        RestTemplate restTemplate = new RestTemplate();
        User user = restTemplate.getForObject(
                "http://localhost:8012/annotation/{id}",
                User.class, id
        );
        System.out.println(user.getUserName());
        return user;
    }
}

输出的日志结果:

14:10:42.839 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP GET http://localhost:8012/annotation/1
14:10:42.904 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[application/json, application/*+json]
14:10:42.921 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
14:10:42.924 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [com.quan.annotationredis.entity.User]
gangganghao

 

多个参数的时候:

@RestController
@RequestMapping("annotation")
public class RedisUserController {
    @Autowired
    private UserService userService =null;

    @PostMapping("/{userName}/{note}")
    public User insertUser(
            @PathVariable ("userName") String userName,
            @PathVariable ("note") String note
    ){
        User user = new User();
        user.setUserName(userName);
        user.setNote(note);
        userService.insertUser(user);
        return user;
    }

 

将参数用一个Map对象封装起来,Map的键名称和URI中所定义的参数时保持一致的。这样子就能将参数统一封装到Map中了

    /**
     *因为我们的Controller层返回的是User类型,所以我们这里也放回User,并使用ResponseEntity<User>接受
     * postForEntity ,通过post请求返回一个实体类,需要url,请求类型,返回类型,参数列表
     * responseEntity.getBody();通过类的方法从返回体里面拿到返回体的内容。(contorller里面是返回user)
     * @return
     */
    public static User  insertUser(){
        RestTemplate restTemplate = new RestTemplate();
        String userName = "huolalala";
        String note = "huolalanote";
        String url = "http://localhost:8012/annotation/{userName}/{note}";

        Map<String,Object> params = new HashMap<>();
        params.put("userName",userName);
        params.put("note",note);

        ResponseEntity<User> responseEntity = restTemplate.postForEntity(url,User.class,User.class,params);
        User user = responseEntity.getBody();
        System.out.println(user);
        return user;
    }

运行日志;

14:55:47.888 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP POST http://localhost:8012/annotation/huolalala/huolalanote
14:55:47.948 [main] DEBUG org.springframework.web.client.RestTemplate - Accept=[application/json, application/*+json]
14:55:47.966 [main] DEBUG org.springframework.web.client.RestTemplate - Writing [class com.quan.annotationredis.entity.User] with org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
14:55:47.987 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK
14:55:47.990 [main] DEBUG org.springframework.web.client.RestTemplate - Reading to [com.quan.annotationredis.entity.User]
User{id=49, userName='huolalala', note='huolalanote'}

 

请求体获取参数:

  /**
     * 11先定义请求头HttpHeaders,设置请求体为JSON格式
     * 22将请求体实体user和请求头绑定到请求实体对象HttpEntiry
     * 33restTemplate.postForObject将请求对象传递过去,
     * @return
     */
    public static User insertUser1(){
        User user = new User();
        user.setNote("RRRR");
        user.setUserName("QQQQ");

        HttpHeaders httpheaders = new HttpHeaders();
        httpheaders.setContentType(MediaType.APPLICATION_JSON_UTF8);

        HttpEntity<User> httpEntity = new HttpEntity<>(user,httpheaders);

        RestTemplate restTemplate = new RestTemplate();
        restTemplate.postForObject("http://localhost:8012/annotation",httpEntity,User.class);

        return user;

    }

 

 

 

 

删除:

 

    /**
     *
     */
    public static void delUser(){
        Long id = 48L;
        RestTemplate restTemplate = new RestTemplate();
        String url = "http://localhost:8012/annotation/{id}";
        restTemplate.delete(url,id);//这个方法没有返回值
    }

运行日志:

17:09:06.618 [main] DEBUG org.springframework.web.client.RestTemplate - HTTP DELETE http://localhost:8012/annotation/48
17:09:06.639 [main] DEBUG org.springframework.web.client.RestTemplate - Response 200 OK

 

posted @ 2020-09-06 20:16  小丑quan  阅读(185)  评论(0)    收藏  举报