框架技术SpringBoot ---- RESTful架构风格【vue和springBoot配合】

SpringBoot框架

内容管理

    • 接口的架构风格----RESTful
      • REST介绍
      • RESTful的注解
        • @PathVariable 获取url中数据
        • @RestController @Controller和@Responsebody复合注解
        • @GetMapping get请求 等同于@RequestMapping(method=RequestMethod.GET)
        • @PostMapping post请求
        • @PutMapping put请求
        • @DeleteMapping delete请求
    • @PathVariable和路径占位符{...}
      • 使用@RequestBody接收JSON对象数据
        • 报错:java.lang.IllegalArgumentException: Invalid character found in method name [.... ]. HTTP method names must be tokens
      • 在普通的前台页面中支持put、delete ---- SpringMVC过滤器HiddenHttpMethodFilter
      • REST风格必须保证http动作 + url的唯一性


SpringBoot接口架构风格 ----- RESTful


再用一点点时间分享一下SpringBoot就准备开启计算机基础的回顾了【计算机基础 + 项目 + 算法 — 以后每篇计算机基础下面都会简单分享算法题】; 项目则会同时进行

就我自己的感觉来说: SpringBoot和SSM相比没有太大的变化,但是确实是简化了许多操作【这种简化的致使programmer做的越来越少; 更加专注于业务逻辑和其他的高并发的思考;SSM的弊端就是限制了很多,首先就是繁琐的配置,其次就是固定的框架,只能使用SpringMVC和Mybatis;如果想使用hibernate,那么就要使用SSH框架; 而SpringBoot就不同了,SpringBoot就是一个Spirng的不重复造轮子思想的体现 — 它可以使用Starter来完美的使用其他的框架,不像SSM已经固定好技术框架;

SpringBoot的两个重要的变化就是配置类JavaConfig;还有就是起步依赖starter;其他的变化其实没有太大;核心都没有变: IOC,DI,AOP等

接口的架构风格----RESTful

接口 ---- 也就是API,应用程序接口,刚接触java的时候就经常听到这个概念,但是当时理解不深刻,只是觉得就是java的核心类库的API,但是后面上手了Vue之后,才感觉明显;因为Vue的概念就是前端工程化的思想;前后端分离,并且大概率是部署在不同的服务器【使用ngix解决跨域,或者后端开启访问】,那么这个时候后端发挥的功能就是返回一些数据,前端通过axios接收即可;后端只需要给前端提供一份api文档,就是一份约定,来完美衔接前端和后端的程序

所谓的无需访问源码,也就是只用调用即可,因为具体功能api文档会说明,前端程序员也大概率看不到后端的源码【访问的url或者其他程序的接口】

架构风格: api的组织方式; 比如一个url地址,地址提供了访问资源名称addStudent后面?get传递参数

REST介绍

Representational State Transfer【表现层状态转移】 一种互联网软件架构设计的风格,不是标准,只是提出了一组客户端和服务器交互时的架构理念和设计的原则;基于这种理念和原则设计的接口可以更简洁,有层次

表现层状态转移:

  • 表现层就是view层—视图层,显示资源,通过视图页面,比如前端的html页面展示;
  • 状态: 资源变化
  • 转移: 资源是可变化的,资源能够创建,new状态,资源创建后可以查询资源,能看到资源的内容,这个资源的内容,可以被修改,修改之后资源和之前的不一样 【也就是http动作操作改变资源】 — 对于同一个资源,发送不同类型的请求,得到的资源发生变化

任何一个技术都可以实现这种理念,如果符合REST原则,那么称为RESTful架构;用REST表示资源和对资源的操作

比如原来访问http接口:

http://localhost:8080/boot/order?id=1021&status=1

采用RESTful架构的风格的接口:

http://localhost:8080/boot/order/1021/1

:happy:,博主之前vue中就已经在大量使用了;比如但是的动态路由: http:…/:id 就是RESTful架构;

之前的普通架构就是: 每一个方法对应的就是对资源的操作比如CRUD;

那么REST中,资源是使用url表示,通过名词表示资源;使用http的动作,表示对资源的操作,但是操作的资源都是相同的

【这部分知识对应的就是前端的axios访问的方式: axios.get; post, delete,put】

这里可以演示一下对于学生的CRUD

GET: 查询资源 sql query

http://localhost:8080/bootOrm/student/1 //这里的1就是学生的id,代表查询这个学生的资源

http://localhost:8080/bootOrm/student/1/HC2001 //可以再加上一个属性

处理多个资源: 使用复数形式

http://localhost:8080/bootOrm/students/1/2 查询id为1和2的学生

POST : 创建资源 sql insert

http://localhost:8080/bootOrm/student //这里使用post提交数据,那么就是创建操作,就直接是student




PUT: 更新资源 sql update

在使用原生js的时候,因为是不能直接使用put和delete,所以需要在表单中hidden隐藏域来表示

<form>
    姓名: <input type='text' name='name'/>
    年龄: <input tupe='text' name='age'/>
    <input type='hidden' name="_method" value='PUT'/>
form>

DELETE: 删除资源 sql delete

http://localhost:8080/bootOrm/student/1 直接访问该链接代表删除学号为1的学员

如果需要进行分页、排序的参数,依然放在url的后面,还是?的方式

http://localhost:8080/bootOrm/student/1?page=1&pageSize=20

RESTful的注解

@PathVariable 获取url中数据

之前使用的是?的方式来进行参数的传递,所以后端就可以使用request.getParameter()来获取数据,但是现在数据直接就在url中,不能通过这种方式进行获取了,现在获取数据需要使用注解@PathVariable ---- 路径变量,就是路径中的数据

获取url中的数据,该注解是实现RESTful最主要的一个注解

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PathVariable {
    @AliasFor("name")
    String value() default ""; //指定变量

    @AliasFor("value")
    String name() default "";

    boolean required() default true;
} //这里就是指定value和name;键值对

@RestController @Controller和@Responsebody复合注解

这个注解放在类的上面,创建控制层对象,同时类中的所有控制器方法都会默认有@ResponseBody,所有的返回值都直接输出到响应体,对象类型就会变为JSON格式,不需要配置driven,SpringBoot帮忙做了很多事情,包括jarkson依赖

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller  //这两个注解的复合注解
@ResponseBody
public @interface RestController {

@GetMapping get请求 等同于@RequestMapping(method=RequestMethod.GET)

支持get请求的方式,等同于@RequestMapping(method=RequestMethod.GET),直接将前端get的路径放入即可

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(  //说明这个注解和这个是相同的作用
    method = {RequestMethod.GET}
)
public @interface GetMapping {

@PostMapping post请求

支持post请求得方式,等同于@RequestMapping(method=RequestMethod.POST)

@PutMapping put请求

支持put请求方式,等同于@RequestMapping(method=RequestMethod.PUT)

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(
    method = {RequestMethod.PUT}
)
public @interface PutMapping {

@DeleteMapping delete请求

支持delete请求方式 等同于@RequestMapping(method=RequestMethod.DELETE)

使用CTRL + N查看这些注解的原型

@PathVariable和路径占位符{…}

前端vue的路径就是RESTful风格的,对于动态路由,前端使用的也是动态匹配

比如: http://localhost:8080/bootOrm/student/:id

这里每次就是访问不同的学生的时候,前端就会给id传入不同的值,如果开启props传参,就可以直接接收,使用axios发送http请求,将props参数拼接在后面

类似的,后端处理器也会使用路径占位符来接收动态的参数;就一个{}即可,和vue插值表达式类似但少一层

比如这里: /student/{stuno};

@PathVariable放在控制器方法的形参前面,通过value指定上面占位符的路径变量,赋值给后面的形参;类似之前的controller中的@RequestParam和之前的mybatis中的@Param【校正赋值】

@RestController
public class StudentController {

    @Resource
    private StudentService studentService;

    //查询学生;接收的get请求
    @GetMapping("/student/{stuName}")
    public Student queryStudent(@PathVariable("stuName") String stuName){
        return studentService.queryStudent(stuName);
    }

使用@RestController就不需要@ResponseBody再注解了

前端访问地址,发送get请求,就可以查询数据

http://localhost:8081/bootOrm/student/王6

{"stuno":2,"stuname":"王6","stuclass":"HC2004"}

可以对比之前的操做的接口风格

 @RequestMapping("/student/query")
    @ResponseBody
    public Student searchStudent(String stuName) {
        return studentService.queryStudent(stuName);
    }

    @RequestMapping("/student/add")

CRUD分别对应的是不同的路径,这显得非常的繁琐,REST风格的接口确实简单了许多

再来康康创建资源的post请求

使用@RequestBody接收JSON对象数据

对于前端直接post的JSON格式的数据,后台显然不能直接使用@PathVariable逐个接收,这个时候使用之前的@RequestBody来接收;⚠: 这个注解会接收所有响应体中的JSON数据然后赋值给对象,所以就不能再用RequestParam来接收了

但是需要注意的是,这个注解接收的是前端转换的JSON格式的数据,而不是将get类似的N=V&N=V的方式

POST /bootOrm/student HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://localhost:8081/bootOrm/
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 37

stuno=12&stuname=Clie&stuclass=HC2001

比如这里就会请求失败,不是JSON格式

  methods:{
	  async postBlog() {
		  //这里使用网址测试https://jsonplaceholder.typicode.com/posts
		  // const {data:res} = await this.$ajax.post('https://jsonplaceholder.typicode.com/posts',{
			 //  title: this.blog.title,
			 //  body: this.blog.content,
			 //  userId:1,
		  // })
		  const res = await this.$ajax.post("http://localhost:8081/bootOrm/student",{
			  stuno: 12,
			  stuname: 'Clie',
			  stuclass: 'HC2001'
		  })

这里使用vue的anxios发送请求,后台;注意,这里的端口号不一致,存在跨域问题:happy:

Access to XMLHttpRequest at 'http://localhost:8081/bootOrm/student' from origin 'http://localhost:3000' has been blocked by CORS policy

所以vue中需要在vue.config中配置

proxy: 'http://localhost:8081'   // proxy代理解决跨域传递   之前这里忘记给注释加//导致这行代码不生效

axios.defaults.baseURL = '/bootOrm'

  const res = await this.$ajax.post("/student",{
			  stuno: 12,
			  stuname: 'Clie',
			  stuclass: 'HC2001'
		  })

配置后正常访问

    @PostMapping("/student")
    public int addStudent(@RequestBody Student student) {
        return studentService.addStudent(student);
    }

后台数据库操作日志

JDBC Connection [HikariProxyConnection@987910987 wrapping com.mysql.cj.jdbc.ConnectionImpl@181b1187] will be managed by Spring
==>  Preparing: INSERT INTO student (stuno,stuname,stuclass) VALUES (?,?,?)
==> Parameters: 12(Integer), Clie(String), HC2001(String)
<==    Updates: 1

报错:java.lang.IllegalArgumentException: Invalid character found in method name [… ]. HTTP method names must be tokens

这里很简单的问题:invalid character,Http method name,说名可能是路径中有字符的问题,是因为前台和后台请求的协议不一致;前台是https,后台是http

再康康删除

删除就是前台发起delete请求,后台用相应的处理器方法执行即可

    //删除学生,接收的是delete请求
    @GetMapping("/student/{stuName}")
    public Student removeStudent(@PathVariable("stuName") String stuName){
        return studentService.removeStudent(stuName);
    }

所以,REST风格更加简便,但是后台的处理器方法并不会减少,还是之前的,只是请求的接口更规范,可能多个处理器方法接收的是同一个url,但是因为http动作不同,所以执行的处理器方法不同; 这样url地址就不会出现多级,并且利于和前台vue配合

在普通的前台页面中支持put、delete ---- SpringMVC过滤器HiddenHttpMethodFilter

默认情况下,浏览器只能发送get和post请求,put、delete请求不支持

在SpringMVC中有一个过滤器,支持post请求转为put等,这个过滤器是内置写好的,HiddenHttpMethodFilter

如果是SSM项目,那么就需要在xml中进行配置,在SpringBoot中就很easy了,在application.yml中配置即可;

  • 前台页面中,还是要像上面的表单一样,加上hidden,指定method;这样后台才可接收
    <form action="/bootOrm/student/query" method="post">
        请输入修改姓名:<input type="text" name="stuName"><br>
        <input type="submit" style="color: black;background-color: aquamarine" value="查询">
        
        <input type="hidden" name="_method" value="put"/>
    form>
  • springboot的yml中开启hidden过滤器
spring:
  mvc:
    hiddenmethod:
      filter:
        enabled: true   #默认是关闭的

这样就可以支持put请求操作

REST风格必须保证http动作 + url的唯一性

REST风格虽然简化了很多,但是也有一定的问题,需要programmer避免,那就是http动作 + url的唯一性;比如现在举个例子

    //查询学生 byName
    @GetMapping("/student/{stuName}")
    public Student queryStudent(@PathVariable("stuName") String stuName){
        return studentService.queryStudent(stuName);
    }

    //查询学生;byAge
    @GetMapping("/student/{stuAge}")
    public Student queryStudentByAge(@PathVariable("stuAge") String stuAge){
        return studentService.queryStudent(stuAge);
    }

可以看到这两个方法不能保证唯一性,如果访问http://localhost:8080/bootOrm/student/20; 那么后台就会报错,因为不知道执行哪个处理器方法,所以设计的时候要注意唯一性

你可能感兴趣的:(JAVAweb,vue.js,spring,boot,java,java-ee,web)