RestController详解(上)

最近在网易云课堂上看一些视频,给大家推荐一个讲Spring Boot的视频https://study.163.com/course/courseMain.htm?courseId=1005213034,老师讲的很不错。在学习的时候我也会做一些笔记,方便日后巩固。
对这个系列感兴趣的可以看我之前写的博客:

开始一个最简单的RESTful API项目

在程序中记录日志

  • 有两种方法,分别依赖两个包,他们是Commons-logging和SLF4j。使用方法:

    private static final Log log = LogFactory.getLog(Xxxx.class);
    private static final Logger logger = LoggerFactory.getLogger(Xxxx.class);
    
  • 日志级别:可以选择某个级别及以上的日志进行记录,这点比单纯的用System.out.print()要好。TRACE和FATAL是Commons-logging包独有的

    TRACE < DEBUG < INFO < WARN < ERROR < FATAL

  • 需要在application.yml中进行配置,下面是参考:

    logging:
    file: target/app.log
    level:
      ROOT: WARN
      cn.luxiaofen: TRACE  #改成对应的包的名字
    

commons-logging

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SampleClass {
    //这是一个不变的对象。修饰为static是因为允许静态方法调用
    private static final Log log = LogFactory.getLog(SampleClass.class);
    
    public void print(String name) {
        if(log.isTraceEnabled()) {
            log.trace("传入参数是: " + name);
        }
        
        try {
            // do something
        }catch(Exception e) {
            if(log.isErrorEnabled()) {
                log.error("出错啦", e);
            }
        }
    }

    … …
}

在getAll()方法中测试

RestController详解(上)_第1张图片
课时6.1

启动Spring Boot后,在浏览器中打开http://localhost:8080/tvseries

RestController详解(上)_第2张图片
课时6.2

注意这个下载的项目设置的编码形式为UTF-8,不支持其他编码形式。如需修改就去.pom文件里改。

使用POSTMAN来测试API

请求方式不止GET这一种,如果是其他的如POST,DELETE,PUT这种就不能单纯的用浏览器去测试。这时候就需要一些工具来帮助我们。一个是命令行工具UNIX系统自带的curl,因为我的系统是WIN10,所以接下来我主要会用到的是一个带界面的API测试工具POSTMAN。

RestController详解(上)_第3张图片
POSTMAN

详解RestController中获取请求的各种数据

请求方式的POST,GET,PUT,DELETE形式分别对应着C(create),R(retrieve),U(update),D(delete)。下面来看看这些方法的实现。

GET方法

  1. 首先对代码做一些重构,这是为了方便将各种TvSeriesDto对象放入list:


    RestController详解(上)_第4张图片
    课时8.1
  2. 添加一个从list中取得一个TvSeriesDto对象的方法


    RestController详解(上)_第5张图片
    课时8.2
  3. 启动Spring Boot后,在POSTMAN中测试


    RestController详解(上)_第6张图片
    课时8.3

POST方法

  1. 在Controller中新增一个POST方法


    RestController详解(上)_第7张图片
    课时8.4
  2. 为了方便测试需要重写TvSeriesDto的toString()方法

    @Override
    public String toString() {
        return this.getClass().getName()+"{id:"+id+",name:"+name+"}";
    }
    
  3. 在POSTMAN中测试


    RestController详解(上)_第8张图片
    课时8.5
  4. 看一下日志

    传进来的参数是:cn.luxiaofen.test.TvSeriesDto{id:0,name:可爱的湖南人}
    

PUT方法

  1. 在Controller中新增PUT方法
    @PutMapping("/{id}")
    public TvSeriesDto updateOne(@PathVariable int id,@RequestBody TvSeriesDto tvSeriesDto) {
        if (log.isTraceEnabled()) {
            log.trace("update one "+id);
        }
        if (id==1 || id ==2) {
            tvSeriesDto.setName("NanNan");//更新数据
            return tvSeriesDto;
        }else
            throw new ResourceNotFoundException();
    }
    
  2. 在POSTMAN中测试


    RestController详解(上)_第9张图片
    课时8.6

DELETE方法

  1. 新增DELETE方法

    /**
     *
     * @param id 在url中的id
     * @param request 这个参数不用加注解,spring会自动传进来
     * @param deleteReason 删除的理由,required = false表示不是必需的
     * @return 删除的信息,储存在MAP中
     */
    @DeleteMapping("/{id}")
    public Map deleteOne(@PathVariable int id, HttpServletRequest request,
                                        @RequestParam(name = "deleteReason",required = false)String deleteReason) throws Exception {
        if(log.isTraceEnabled()) {
            log.trace("delete one "+id);
        }
    
    
        Map result = new HashMap<>();
        if (id == 2) {
            // TODO:执行删除的代码
            result.put("message","#2被"+request.getRemoteAddr()+"删除,原因("+deleteReason+")");
        }else if (id == 1) {
            throw new RuntimeException("LoveManchester不能被删除");
        }else
            throw new ResourceNotFoundException();
    
        return result;
    }
    
  2. 在POSTMAN中测试,注意这里request parameter不能使用中文,会引起编码错误


    RestController详解(上)_第10张图片
    课时8.7
  3. 查看日志

    2018-11-10 09:46:15.693 DEBUG 8300 --- [nio-8080-exec-1] cn.luxiaofen.test.TvSeriesController     : delete one 2
    

RestController中的上传和下载示例

上传文件

  1. 为了使用org.apache.commons.io包下的IOUtils,需要在MAVEN中引入这个包,在.pom文件中加入:

    
    
        commons-io
        commons-io
        2.4
    
    
  2. 在Controller中新增文件上传方法

    /**
     * 这是一个上传照片的方法
     * consumes表示传入的参数,这里采用的是MULTIPART_FORM_DATA_VALUE类型
     * @param photo 上传的照片
     */
    @PostMapping(value = "/photo",consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public void addPhoto(@RequestParam("photo")MultipartFile photo) throws IOException {
        if (log.isTraceEnabled()) {
            log.trace("接收到文件"+photo.getOriginalFilename());
        }
    
        //保存文件到指定目录下
        FileOutputStream fos = new FileOutputStream("target/"+photo.getOriginalFilename());
        //注意这里引用的包是org.apache.commons.io.IOUtils
        IOUtils.copy(photo.getInputStream(),fos);
        fos.close();
    }
    
  3. 在POSTMAN中测试


    RestController详解(上)_第11张图片
    课时9.1
  4. 看一下IDEA中的结果:

    2018-11-10 11:18:31.941 DEBUG 3420 --- [nio-8080-exec-1] cn.luxiaofen.test.TvSeriesController     : 接收到文件nannan.jpg
    
    RestController详解(上)_第12张图片
    课时9.2

下载文件

  1. 在src/main/resources目录下储存一张图片,命名为icon.jpg
  2. 增加下载文件的方法
    /**
     * 这是一个返回数据的方法
     * produces参数表示生成的文件格式,这里使用的是jpg文件格式
     * @return 图片
     */
    @GetMapping(value = "/icon",produces = MediaType.IMAGE_JPEG_VALUE)
    public byte[] getIcon() throws IOException {
        if (log.isTraceEnabled()) {
            log.trace("getIcon() is invoked");
        }
    
        //需要在指定目录下预先放好文件
        String iconFile = "src/main/resources/icon.jpg";
        InputStream inputStream = new FileInputStream(iconFile);
        return IOUtils.toByteArray(inputStream);
    }
    
  3. 浏览器中打开http://localhost:8080/tvseries/icon,看到浏览器中已经返回了我们预先储存的图片
    RestController详解(上)_第13张图片
    课时9.3
  4. 在IDEA中查看日志
    2018-11-10 12:05:26.622 DEBUG 6412 --- [nio-8080-exec-2] cn.luxiaofen.test.TvSeriesController     : getIcon() is invoked
    

在RestController中获取各种相关信息的⽅法

  • URL中路径的⼀部分:

    ⾸先需要在RequestMapping做映射,之后在⽅法中可以通过注解使⽤映射的变量

    @GetMapping("/{id}")
    public TvSeries getOne(@PathVariable("id") Integer id){}
    

    可以写多个: @PutMapping("/{id}/characters/{cId}")

    还可以使⽤正则表达式限制类型(不符合要求会返回4xx的错误信息,表示请求参数
    有问题)此例⼦表示id必须是数字:
    @PutMapping("/{id:\d+}")

  • POST⽅法传递过来的JSON:

    给参数前增加@RequestBody注解, Spring会⾃动把POST的Request Body部分的JSON转成⽅法声明的类。如果转化失败会返回4xx错误,表示请求参数有问题。

    public Object updateOne(@RequestBody TvSeries tvSeries)
    
  • POST⽅法传递的是表单数据:

    ⾸先需要声明传⼊的是application/x-www-form-urlencoded的格式,可在RequestMapping增加consumes参数:

    @PostMapping(value="/tvseries",consumes=MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    

    在⽅法上增加参数,参数使⽤@RequestParam注解即可:

    public Object insert(@RequestParam(value="name",required=false) String name) {}
    

    凡是可以通过HttpServletRequest.getParameter(String)⽅法取到的值,
    包含表单提交的、 QueryString附带的,都可以使⽤@RequestParam注解得到
    默认是request=true。

  • QueryString的参数:

    使⽤@RequestParam注解,通过参数获得,例如:

    public Object query(@RequestParam(value="page",required=false) Integer page)
    
  • Request Header:

    可以使⽤@Requestheader注解获取Request的头信息,例如:

    public ResultJSON editCompany(@RequestHeader("user-agent")String userAgent) {}
    

    注意: @RequestHeader后⾯的头名字不区分⼤⼩写,但RequestParam,PathVariable等是区分的。
    如果RequestHeader后⾯不写参数,会⽤后⾯的变量名替代

  • 获取cookie值:

    使⽤@CookieValue注解,和其他类似,除⾮为了兼容⽼现有客户端,新API⾥不建议⽤cookie。

  • 获取当前的RequestResponse:

    直接写参数,例如:

    public Object doSomething(HttpServletRequest request,HttpServletResponse response){}
    
  • 获取当前⽤户:

    直接在⽅法上增加参数,类型为:org.springframework.security.core.Authentication,例如:

    public TvSeries deleteOne(Authentication auth)
    

    参数auth内会存储有当前的⽤户信息。

  • ⽂件上传:

    ⾸先要设置consumes为multipart/form-data:

    @PostMapping(value="/files",consumes=MediaType.MULTIPART_FORM_DATA_VALUE)
    

    在⽅法中写参数:

    public Map uploadFile(@RequestParam("file")MultipartFile file)
    

    在⽅法中可以直接使⽤MultipartFile中的流保存⽂件了。

你可能感兴趣的:(RestController详解(上))