【SpringMVC】| RESTful架构风格、RESTful案例(CRUD)
作者:mmseoamin日期:2023-12-14

目录  

RESTful架构风格

1. RESTful简介

2. RESTful的实现

3. HiddenHttpMethodFilter

RESTful案例(CRUD)

1. 准备工作

2. 功能清单

列表功能(显示数据) 

删除数据(难点)

添加数据 

更新数据

图书推荐:用ChatGPT与VBA一键搞定Excel


RESTful架构风格

1. RESTful简介

REST:Representational State Transfer,表现层资源状态转移。

a>资源

        资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端应用开发者能够理解。与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个资源可以由一个或多个URI来标识。URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互。

b>资源的表述

        资源的表述是一段对于资源在某个特定时刻的状态的描述。可以在客户端-服务器端之间转移(交换)。资源的表述可以有多种格式,例如:HTML/XML/JSON/纯文本/图片/视频/音频等等。资源的表述格式可以通过协商机制来确定。请求-响应方向的表述通常使用不同的格式。

c>状态转移

        状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述,来间接实现操作资源的目的。

2. RESTful的实现

(1)具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。

(2)REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开(前端是一杠一值、后端是一杠一大括号),不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性。

操作传统方式REST风格
查询操作getUserById?id=1user/1-->get请求方式
保存操作saveUseruser-->post请求方式
删除操作deleteUser?id=1user/1-->delete请求方式
更新操作updateUseruser-->put请求方式

3. HiddenHttpMethodFilter

(1)由于浏览器只支持发送get和post方式的请求,那么该如何发送put和delete请求呢SpringMVC 提供了 HiddenHttpMethodFilter 帮助我们将 POST 请求转换为 DELETE 或 PUT 请求!

(2)HiddenHttpMethodFilter 处理put和delete请求的条件:

①当前请求的请求方式必须为:post;

②当前请求必须传输请求参数:_method(这个参数有三个值:put、delete、patch)。

(3)满足以上条件,HiddenHttpMethodFilter 过滤器就会将当前请求的请求方式转换为请求参数_method的值,因此请求参数_method的值才是最终的请求方式。

 在web.xml中注册HiddenHttpMethodFilter

    
        HiddenHttpMethodFilter
        org.springframework.web.filter.HiddenHttpMethodFilter
    
    
        HiddenHttpMethodFilter
        /*
    

注:目前为止,SpringMVC中提供了两个过滤器:CharacterEncodingFilter和HiddenHttpMethodFilter在web.xml中注册时,必须先注册CharacterEncodingFilter,再注册HiddenHttpMethodFilter。

原因:在 CharacterEncodingFilter 中通过 request.setCharacterEncoding(encoding) 方法设置字符集的;request.setCharacterEncoding(encoding) 方法要求前面不能有任何获取请求参数的操作; 而 HiddenHttpMethodFilter 恰恰有一个获取请求方式的操作:

String paramValue = request.getParameter(this.methodParam);

发送Get、Post、Put、Delete请求实操

前端发送请求:




    
    Title



查询所有用户信息
根据id查询用户信息
用户:
密码:


用户:
密码:



后端接收请求:

注:执行删除操作时一般都是使用超链接,但是一般都是和Vue或者ajax相关联;这里就是用form表单的形式,但是使用form表单执行删除操作时,不能使用@RequestMappping注解,然后method属性去指定请求的方式(会报错)。直接使用派生注解@DeleteMapping就没事

package com.zl.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
 * 使用Restful模拟用户资源的增删改查
 * /user    Get     查询所有用户信息
 * /user/1  Get     根据用户id查询用户信息
 * /user    Post    添加用户信息
 * /user/1  Delete  根据用户id删除用户信息
 * /user    Put     修改用户信息
 */
@Controller
public class UserController {
    @RequestMapping("/")
    public String forwardIndex(){
        return "index";
    }
    // 发送Get查询所有
    @RequestMapping(value = "/user",method = RequestMethod.GET)
    public String getAllUser(){
        System.out.println("查询所有用户信息");
        return "success";
    }
    // 发送Get查询一个
    @RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
    public String getUserById(@PathVariable String id){
        System.out.println("根据用户id查询用户信息"+id);
        return "success";
    }
    // 发送Post增加
    @RequestMapping(value = "/user",method = RequestMethod.POST)
    public String insertUser(String username,String password){
        System.out.println("成功添加用户:"+username+"密码是:"+password);
        return "success";
    }
    // 发送put修改
    @RequestMapping(value = "/user",method = RequestMethod.PUT)
    public String putUser(){
        System.out.println("修改用户信息");
        return "success";
    }
    // 发送Delete删除
    // @RequestMapping(value = "/user/{id}}",method = RequestMethod.DELETE)
    @DeleteMapping(value = "/user/{id}")
    public String deleteUserById(@PathVariable String id){
        System.out.println("根据用户id删除用户信息:"+id);
        return "success";
    }
}

RESTful案例(CRUD)

1. 准备工作

搭建环境

pom.xml



  4.0.0
  org.example
  springmvc-thymeleaf-restful
  1.0-SNAPSHOT
  war
  springmvc-thymeleaf-restful Maven Webapp
  
  http://www.example.com
  
    UTF-8
    1.8
    1.8
  
  
    
      org.springframework
      spring-webmvc
      5.2.5.RELEASE
    
    
      javax.servlet
      javax.servlet-api
      3.1.0
    
    
      org.thymeleaf
      thymeleaf-spring5
      3.0.10.RELEASE
    
    
      ch.qos.logback
      logback-classic
      1.2.3
    
  
  
  
    
      
        src/main/java
        
          **/*.xml
          **/*.properties
        
      
      
        src/main/resources
        
          **/*.xml
          **/*.properties
        
      
    
  

web.xml 



    
    
        encode
        org.springframework.web.filter.CharacterEncodingFilter
        
        
            encoding
            utf-8
        
        
        
            forceRequestEncoding
            true
        
        
        
            forceResponseEncoding
            true
        
    
    
    
        encode
        /*
    
    
    
        HiddenHttpMethodFilter
        org.springframework.web.filter.HiddenHttpMethodFilter
    
    
        HiddenHttpMethodFilter
        /*
    
    
    
        springmvc
        org.springframework.web.servlet.DispatcherServlet
        
        
            contextConfigLocation
            classpath:springmvc.xml
        
        
        1
    
    
        springmvc
        
        /
    

springmvc.xml



    
    
    
    
    
    
    
    
    
    
        
        
        
            
                
                    
                        
                        
                        
                        
                        
                        
                    
                
            
        
    

准备实体类

package com.zl.bean;
public class Employee {
    private Integer id;
    private String lastName;
    private String email;
    private Integer gender;
    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", lastName='" + lastName + '\'' +
                ", email='" + email + '\'' +
                ", gender=" + gender +
                '}';
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public Integer getGender() {
        return gender;
    }
    public void setGender(Integer gender) {
        this.gender = gender;
    }
    public Employee(Integer id, String lastName, String email, Integer gender) {
        super();
        this.id = id;
        this.lastName = lastName;
        this.email = email;
        this.gender = gender;
    }
    public Employee() {
    }
}

准备dao模拟数据:使用Map集合的操作模拟连接数据库

package com.zl.dao;
import com.zl.bean.Employee;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@Repository
public class EmployeeDao {
    private static Map employees = null;
    static{
        employees = new HashMap();
        employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1));
        employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1));
        employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0));
        employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0));
        employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1));
    }
    private static Integer initId = 1006;
    public void save(Employee employee){
        if(employee.getId() == null){
            employee.setId(initId++);
        }
        employees.put(employee.getId(), employee);
    }
    public Collection getAll(){
        return employees.values();
    }
    public Employee get(Integer id){
        return employees.get(id);
    }
    public void delete(Integer id){
        employees.remove(id);
    }
}

2. 功能清单

功能URL 地址请求方式
访问首页√/GET
查询全部数据√/employeeGET
删除√/employee/2DELETE
跳转到添加数据页面√/toAddGET
执行保存√/employeePOST
跳转到更新数据页面√/employee/2GET
执行更新√/employeePUT

列表功能(显示数据) 

index.html:发送请求,查询所有员工




    
    Title


首页

查看员工信息

EmployeeController:接收请求,拿到数据放到域对象当中去;并跳转页面展示数据

package com.zl.controller;
import com.zl.bean.Employee;
import com.zl.dao.EmployeeDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Collection;
import java.util.Iterator;
@Controller
public class EmployeeController {
    @Autowired
    private EmployeeDao employeeDao;
    // 查看员工信息
    @GetMapping("/employee")
    public String getEmployees(Model model){
        Collection employees = employeeDao.getAll();
        System.out.println(employees);
        // 放到域对象当中
        model.addAttribute("employees",employees);
        // 跳转页面进行数据的展示
        return "employee_list";
    }
}

employee_list.html:展示数据

①前端中两个重要的标签from和table:from是用来发送请求的,table是用来展示数据的。border属性表示设置边框、cellpadding和cellspacing表示设置边框的边距和间距为0、style是用来设置居中操作的(也可以直接用align="center")。

②使用thymeleaf便利数据,很类似以与JSTL标签库的使用,格式不同罢了;这是使用的是thymeleaf的each标签,格式为:"自定义变量名:放入域对象数据的key"




    
    Employee Info



Employee Info
id lastName email gender options
delete update

效果展示:

【SpringMVC】| RESTful架构风格、RESTful案例(CRUD),第1张

删除数据(难点)

问题:删除操作处理超链接地址?

通过id进行删除操作,但是此时的id需要动态获取,不能写死!

delete

如果直接使用${employee.id}的方式添加在路径后面,此时大括号{}会被thymeleaf解析!

【SpringMVC】| RESTful架构风格、RESTful案例(CRUD),第2张

解决方案一: 使用+号拼接,拼接在@{}外面,这样就不会被thymeleaf解析


delete

解决方案二: 也可以就拼接在@{}里面,此时的路径/employee/需要加上单引号


delete

问题:通过超链接控制表单的提交?

通过Vue实现超链接控制form表单的提交!

注:在webapp/static/js下导入vue.js库!

①首先需要创建Vue,在Vue中绑定容器;我们需要操作超链接,所以绑定的元素必须包括我们要操作的元素。所以可以在tr或者table标签中定义一个id进行绑定。

②设置超链接的点击事件,在删除的超链接中使用@click绑定一个点击事件;然后在Vue的methods种处理绑定事件。

③获取form表单,所以要给from表单设置id,进行获取,获取到表单以后将触发事件的超连接的href属性赋值给表单的action、提交表单、取消超连接的默认行为。




    
    Employee Info



Employee Info
id lastName email gender options
delete update

根据id删除

注:此时会遇到使用转发还是重定向的问题;删除过后就和当前页面没关系,是要跳转到另一个页面,并且地址栏的地址肯定也要变,所以使用重定向!

    // 根据id删除员工
    @DeleteMapping("/employee/{id}")
    public String deleteEmployee(@PathVariable Integer id){
        employeeDao.delete(id);
        // 重定向到列表页面
        return "redirect:/employee";
    }

问题1:此时重新部署进行访问,此时浏览器会报错误(发送的还是get请求,绑定的事件没起作用)

【SpringMVC】| RESTful架构风格、RESTful案例(CRUD),第3张

F12代开调试窗口,发现是找不到vue.js

【SpringMVC】| RESTful架构风格、RESTful案例(CRUD),第4张 此时打开当前工程打的war包发现没有static的目录

【SpringMVC】| RESTful架构风格、RESTful案例(CRUD),第5张

 解决方案:重新进行打包

【SpringMVC】| RESTful架构风格、RESTful案例(CRUD),第6张

问题2: 上面是解决了当前项目没有,所以找不到;重新打包以后当前服务器已经有了,发现还是找不到!

解释:此时是因为前端控制器DispatcherServlet引起的,因为我们设置的处理路径是"/",表示除了jsp的所有路径,此时的静态资源vue.js被SpringMVC处理了,但是静态资源又不能被SpringMVC处理。此时需要一个default-servlet-handler开放对静态资源的访问!


工作的原理:

首先静态资源会被SpringMVC的前端控制器DispatcherServlet处理,如果在前端的控制器中找不到相对应的请求映射,此时就会交给默认的Servlet处理,如果默认的Servlet能找到资源就访问资源,如果找不到就报404!

问题3:此时浏览器还可能报错

解释:您正在开发模式下运行Vue。部署生产时,请确保打开生产模式。

【SpringMVC】| RESTful架构风格、RESTful案例(CRUD),第7张

根据提示来做 , 将生产模式的提示关闭即可 ,即设置成 false即可

 

此时就可以正常的进行删除操作 

【SpringMVC】| RESTful架构风格、RESTful案例(CRUD),第8张

添加数据 

编写超链接,跳转到添加页面

options(add)

此时不需要任何的业务逻辑,使用视图控制器


 添加数据的employee_add




    
    add employee



lastName:
email:
gender:male female

获取form表单提交的数据,进行添加

    // 添加数据
    @PostMapping("/employee")
    public String addEmployee(Employee employee){
        employeeDao.save(employee);
        // 重定向到列表页面
        return "redirect:/employee";
    }

添加成功

【SpringMVC】| RESTful架构风格、RESTful案例(CRUD),第9张

更新数据

根据id进行修改


update

注:这里涉及一个回显数据的功能,所以需要先跳转到一个Controller去查询数据,把数据放到域对象当中后跳转到一个新的页面employee_update页面显示,通过这个页面进行显示的数据进行修改,修改后并提交在经过一个Controller处理冲转到页面展示功能页面进行数据的展示!

根据id先查询数据

   // 用户回显数据的controller
    @RequestMapping("/employee/{id}")
    public String getEmployeeById(@PathVariable Integer id,Model model){
        // 根据id查
        Employee employee = employeeDao.get(id);
        // 存到域对象当中
        model.addAttribute("employee",employee);
        // 跳转到回显数据的页面
        return "employee_update";
    }

回显数据并可以更新数据的employee_update

对于单显框的回显使用的是field属性!




    
    update employee



lastName:
email:
gender:male female

效果展示:默认回显数据的效果

【SpringMVC】| RESTful架构风格、RESTful案例(CRUD),第10张

在上面回显数据的页面进行更新,根据更新提交的数据进行存储,然后重定向到列表页面展示

    // 更新数据的Controller
    @PutMapping("/employee")
    public String updateEmployee(Employee employee){
        // 更新数据
        employeeDao.save(employee);
        // 重定向到列表页面
        return "redirect:/employee";
    }

图书推荐:用ChatGPT与VBA一键搞定Excel

参与方式:

本次送书 1 本! 

活动时间:截止到 2023-06-12 00:00:00。

抽奖方式:利用程序进行抽奖。

参与方式:关注博主(只限粉丝福利哦)、点赞、收藏,评论区随机抽取,最多三条评论!

本期图书:《用ChatGPT与VBA一键搞定Excel》

        在以 ChatGPT 为代表的 AIGC(AI Generated Content,利用人工智能技术来生成内容)工具大量涌现的今天,学习编程的门槛大幅降低。对于大部分没有编程基础的职场人士来说,VBA 这样的办公自动化编程语言比以前任何时候都更容易掌握,能够极大提高工作效率。本书通过 3 个部分:VBA 基础知识、ChatGPT基础知识、ChatGPT实战办公自动化,帮助Excel用户从零开始迅速掌握VBA,以“授人以渔”的方式灵活应对任何需要自动化办公的场景。

        简而言之,本书的目标是:普通用户只需要掌握一些VBA的基本概念,然后借助 ChatGPT 就可以得到相应的VBA代码,从而解决具体问题。

【SpringMVC】| RESTful架构风格、RESTful案例(CRUD),第11张

京东购买链接:点击购买