SpringMVC学习(二)——RESTful API、拦截器、异常处理、数据类型转换

news2025/2/7 10:41:21

一、RESTful 

(一)RESTful概述

        RESTful是一种软件架构风格,用于设计网络应用程序。REST是“Representational State Transfer”的缩写,中文意思是“表现层状态转移”。它基于客户端-服务器模型和无状态操作,以及使用HTTP请求来处理数据。RESTful架构风格强调利用HTTP协议的四个主要方法(GET、POST、PUT、DELETE)来实现资源的访问和操作。以下是RESTful架构的一些核心原则:

  1. 客户端-服务器分离:客户端和服务器之间的交互应该是简单的,服务器端负责存储数据和业务逻辑,客户端负责展示。

  2. 无状态:每个请求从客户端到服务器必须包含所有必要的信息,以便服务器能够理解请求并独立地处理它,不依赖于之前的任何请求。

  3. 可缓存:数据被标记为可缓存或不可缓存。如果数据被标记为可缓存,那么客户端可以缓存数据以提高效率。

  4. 统一接口:系统组件之间的交互通过统一的接口进行,这简化了整体系统架构,使得系统更容易理解、开发和使用。

  5. 分层系统:客户端不能直接了解它所消费的服务之外的任何服务器信息,也不应该知道它的数据是来自一个服务器还是多个服务器。

  6. 按需代码(可选):服务器可以按需向客户端发送代码,比如JavaScript,以便在客户端执行。

        在RESTful架构中,资源(Resources)是核心概念,每个资源都有一个唯一的标识符,通常是一个URI。客户端通过HTTP方法对这些资源进行操作:

  • GET:请求从服务器检索特定资源。GET请求应该是安全的,不会产生副作用。

  • POST:向服务器提交新的资源,通常会导致创建新的资源。

  • PUT:更新服务器上的现有资源。

  • DELETE:从服务器上删除资源。

        RESTful API设计简洁、直观,易于理解和使用,因此在现代网络应用中非常流行

代码示例: 

@CrossOrigin  // 允许跨域请求
@RestController
@RequestMapping("/emp")
public class EmpController {
    @Autowired
    private EmpService empService;

    /**
     * 查询员工
     */
    @GetMapping("/{empno}")
    public R queryEmpById(@PathVariable("empno") Integer empno) {
        Emp emp = empService.queryById(empno);
        return R.ok(emp);
    }

    /**
     * 新增员工
     */
    @PostMapping
    public R addEmp(@RequestBody Emp emp) {
        empService.save(emp);
        return R.ok();
    }

    /**
     * 修改员工
     */
    @PutMapping
    public R editEmp(@RequestBody Emp emp) {
        empService.update(emp);
        return R.ok();
    }

    /**
     * 删除员工
     */
    @DeleteMapping("/{empno}")
    public R deleteEmpById(@PathVariable("empno") Integer empno) {
        empService.deleteById(empno);
        return R.ok();
    }

    /**
     * 查询所有员工
     */
    @GetMapping("/getAll")
    public R queryEmpList() {
        List<Emp> empList = empService.getList();
        return R.ok(empList);
    }
}

(二)@PathVariable:从URL中提取路径变量

        @PathVariable是Spring MVC中用于从URL中提取路径变量的注解。它允许将URL模板中的占位符映射到方法参数,从而实现动态路由和数据传递。
使用场景:

  • RESTful API:在设计RESTful API时,通常会使用@PathVariable来获取资源的唯一标识符(如 ID)。
  • 动态内容:根据 URL 中的变量来动态生成页面或响应内容。

二、拦截器

(一)HandlerInterceptor

        HandlerInterceptor是SpringMVC内置拦截器机制,用于在请求处理的不同阶段插入自定义逻辑。它允许在请求到达控制器之前、控制器处理请求之后以及请求完成之后执行特定的操作。比如:权限验证、日志记录、数据共享等......

使用步骤:

  • 实现HandlerInterceptor接口的组件即可成为拦截器
  • 创建WebMvcConfigurer组件,并配置拦截器的拦截路径
  • 执行顺序:顺序preHandle→目标方法→倒序postHandle→渲染→倒序afterCompletion
  • 只有执行成功的preHandle会倒序执行afterCompletion
  • postHandle、afterCompletion从哪里跑出异常,倒序链路从哪里结束
  • postHandle失败不会影响afterCompletion执行
@Component  // 拦截器还需要配置(告诉SpringMVC,这个拦截器主要拦截什么请求)
public class MyHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyHandlerInterceptor...preHandle...");
        return false; // true表示放行,false表示拦截
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("MyHandlerInterceptor...postHandle...");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("MyHandlerInterceptor...afterCompletion...");
    }
}
@Configuration  // 专门对SpringMVC底层进行配置
public class MySpringMVCConfig implements WebMvcConfigurer {

    @Autowired
    MyHandlerInterceptor myHandlerInterceptor;

    /**
     * 添加拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myHandlerInterceptor)
                .addPathPatterns("/**"); // 拦截所有请求
    }
}
@CrossOrigin  // 允许跨域请求
@RestController
@RequestMapping("/emp")
public class EmpController {
    @Autowired
    private EmpService empService;

    /**
     * 查询员工
     */
    @GetMapping("/{empno}")
    public R queryEmpById(@PathVariable("empno") Integer empno) {
        System.out.println("查询用户。目标方法执行......");
        Emp emp = empService.queryById(empno);
        return R.ok(emp);
    }
}

(二)拦截器与过滤器的区别(面试题) 

三、异常处理

1.编程式异常处理

编程式异常处理:如果大量业务都需要加异常处理代码会很麻烦

@GetMapping("/hello")
public R hello(@RequestParam(value = "i", defaultValue = "0") Integer i) {
    try {
        int j = 10 / i;
        return R.ok(j);
    } catch (Exception e) {
        return R.error(100, "除数不能为0", e.getMessage());
    }
}

2.声明式异常处理

  1. 如果Controller本类出现异常,会自动在本类中找到有没有@ExceptionHandler标注的方法,如果有,执行这个方法,它的返回值,就是客户端收到的结果;如果发生异常,多个都能处理,就精确的优先。
  2. 异常处理的优先级:本类 > 全局;精确 > 模糊
  3. 如果出现了异常:本类和全局都不能处理,SpringBoot底层对SpringMVC有兜底处理机制:自适应处理(浏览器响应页面、移动端响应JSON)
  4. 最佳实践:编写全局异常处理器,处理所有异常
@RestController
public class HelloController {
    @GetMapping("/hello")
    public R hello(@RequestParam(value = "i", defaultValue = "0") Integer i) throws FileNotFoundException {
        int j = 10 / i;
//        FileInputStream fileInputStream = new FileInputStream("C:\\Users\\lxm\\Desktop\\test.txt");
        String str = null;
        str.length();
        return R.ok(j);
    }

    @ExceptionHandler(ArithmeticException.class)
    public R handlerArithmeticException(ArithmeticException e) {
        System.out.println("ArithmeticException异常处理");
        return R.error(100, "除数不能为0", e.getMessage());
    }

    @ExceptionHandler(FileNotFoundException.class)
    public R FileNotFoundException(FileNotFoundException e) {
        System.out.println("FileNotFoundException异常处理");
        return R.error(300, "文件找不到", e.getMessage());
    }

    @ExceptionHandler(Throwable.class)
    public R handlerException(Throwable e) {
        System.out.println("Throwable异常处理");
        return R.error(500, "其他异常", e.getMessage());
    }
}
// @ResponseBody
// @ControllerAdvice   // 告诉SpringMVC,这个类是处理全局异常的
@RestControllerAdvice  // 全局异常处理器:相当于@ControllerAdvice + @ResponseBody
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public R handleException(Throwable e) {
        System.out.println("全局异常处理");
        return R.error(500, e.getMessage());
    }

    @ExceptionHandler(ArithmeticException.class)
    public R handlerArithmeticException(ArithmeticException e) {
        System.out.println("算数异常处理");
        return R.error(100, e.getMessage());
    }
}

3.异常处理的最终方式

  1. 必须有业务异常类:BusinessException
  2. 必须有异常枚举类:BusinessExceptionEnum列举项目中每个模块将会出现的所有异常情况
  3. 编写业务代码的时候,只需编写正确逻辑,如果出现预期的问题,需要以抛异常的方式中断逻辑并通知上层
  4. 全局异常处理器:GlobalExceptionHandler 处理所有异常,返回给前端约定的JSON数据与错误码

异常枚举类: 

public enum BusinessExceptionEnum {
    ORDER_NOT_EXIST(10001, "订单不存在"),
    ORDER_STATUS_ERROR(10002, "订单状态错误"),
    ORDER_UPDATE_ERROR(10003, "订单更新失败"),
    ORDER_DELETE_ERROR(10004, "订单删除失败"),
    ORDER_CREATE_ERROR(10005, "订单创建失败"),
    ORDER_QUERY_ERROR(10006, "订单查询失败"),
    ORDER_PAY_ERROR(10007, "订单支付失败"),
    ORDER_CANCEL_ERROR(10008, "订单取消失败");

    @Getter
    private Integer code;
    @Getter
    private String msg;

    BusinessExceptionEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

全局业务异常类: 

@Data
public class BusinessException extends RuntimeException {
    private Integer code;
    private String msg;

    public BusinessException(Integer code, String msg) {
        super(msg);
        this.code = code;
        this.msg = msg;
    }

    public BusinessException(BusinessExceptionEnum businessExceptionEnum) {
        super(businessExceptionEnum.getMsg());
        this.code = businessExceptionEnum.getCode();
        this.msg = businessExceptionEnum.getMsg();
    }
}

业务代码 

@Override
public void update(Emp emp) {
    // 去数据库查询原来的值
    Integer empno = emp.getEmpno();
    if (empno == null) {
        throw new BusinessException(BusinessExceptionEnum.ORDER_NOT_EXIST);
    }
    Emp empById = empDao.getEmpById(empno);
    if (StringUtils.hasText(empById.getEname())) {
        empById.setEname(emp.getEname());
    }
    empDao.updateEmp(emp);
}

四、SpringMVC原理

五、数据类型转换

1.String转Date类型

@Controller
@RequestMapping("/book")
public class BookController {

    @GetMapping("/jump")
    public String jump(){
        // int i = 1/0;
        return "book/add";
    }

    @PostMapping("/doAdd")
    @ResponseBody
    public BookModel doAdd(BookModel book){
        return book;
    /**
    * {
    *   "id": null,
    *   "name": "红楼梦",
    *   "ctime": 1735228800000
    * }
    */
    }

    @PostMapping("/doAdd2")
    @ResponseBody
    public Date doAdd2(String name,
                       @DateTimeFormat(pattern = "yyyy-MM-dd") Date ctime){
        return ctime; // 1735142400000
    }
}
@Data
public class BookModel {
    private Integer id;
    private String name;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date ctime;
}

2.String转LocalDateTime类型

自定义参数类型转换器:

public class StringToDate implements Converter<String, Date> {
    @Override
    public Date convert(String s) {
        //传入的参数,等待被转换的2024-12-27 字符串
        System.out.println(s);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date date = null;
        try {
            date = simpleDateFormat.parse(s);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        return date;
    }
}


public class StringToDateTime implements Converter<String, LocalDateTime> {
    @Override
    public LocalDateTime convert(String s) {
        return LocalDateTime.parse(s, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
    }
}
@Data
public class BookModel {
    private Integer id;
    private String name;
//    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date ctime;
//    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime utime;
}

3.接收JSON字符串

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.11.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.11.2</version>
</dependency>
/**
 * 接收JSON转换日期时间
 */
@PostMapping("/doAdd3")
@ResponseBody
public BookModel doAdd3(@RequestBody BookModel book){
    return book;
}
@Data
public class BookModel {
    private Integer id;
    private String name;
    // @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date ctime;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime utime;
}

注意:

JSON时间,可以写2024-01-27 09:09:09
不能写 2024-1-27 9:9:9

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2267353.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国内独立开发者案例及免费送独立开发蓝图书

独立开发者在国内越来越受到关注&#xff0c;他们追求的是一种自由且自给自足的工作状态。 送这个&#xff1a; 少楠light&#xff08;Flomo、小报童、如果相机&#xff09;&#xff1a;他们是独立开发者的典范&#xff0c;不仅开发了多款产品&#xff0c;还坚信“剩者为王”…

【JavaEE进阶】@RequestMapping注解

目录 &#x1f4d5;前言 &#x1f334;项目准备 &#x1f332;建立连接 &#x1f6a9;RequestMapping注解 &#x1f6a9;RequestMapping 注解介绍 &#x1f384;RequestMapping是GET还是POST请求&#xff1f; &#x1f6a9;通过Fiddler查看 &#x1f6a9;Postman查看 …

一文详解MacOS+CLion——构建libtorch机器学习开发环境

对于希望在本地环境中进行深度学习开发的开发者来说&#xff0c;配置合适的工具链是至关重要的一步。本文旨在帮助您在 macOS 操作系统上&#xff0c;利用 CLion IDE 和 PyTorch 的 C依赖库——libtorch&#xff0c;快速搭建起一个高效的开发环境。这里我们将一步步地讲解如何下…

Bert中文文本分类

这是一个经典的文本分类问题&#xff0c;使用google的预训练模型BERT中文版bert-base-chinese来做中文文本分类。可以先在Huggingface上下载预训练模型备用。https://huggingface.co/google-bert/bert-base-chinese/tree/main 我使用的训练环境是 pip install torch2.0.0; pi…

shardingsphere分库分表项目实践5-自己用java写一个sql解析器+完整项目源码

前1节我们介绍了 shardingsphere 分表分库的sql解析与重写&#xff1a; shardingsphere分库分表项目实践4-sql解析&重写-CSDN博客 那么shardingsphere sql 解析底层究竟是怎么实现的呢&#xff0c;其实它直接用了著名的开源软件 antlr . antlr 介绍&#xff1a; ANTLR&a…

10分钟掌握项目管理核心工具:WBS、甘特图、关键路径法全解析

一、引言 在项目管理的广阔天地里&#xff0c;犹如一场精心编排的交响乐演奏&#xff0c;每个乐器、每个音符都需精准配合才能奏响美妙乐章。而 WBS&#xff08;工作分解结构&#xff09;、甘特图、关键路径法无疑是这场交响乐中的关键乐章&#xff0c;它们从不同维度为项目管…

【LLM】OpenAI 的DAY12汇总和o3介绍

note o3 体现出的编程和数学能力&#xff0c;不仅达到了 AGI 的门槛&#xff0c;甚至摸到了 ASI&#xff08;超级人工智能&#xff09;的边。 Day 1&#xff1a;o1完全版&#xff0c;开场即巅峰 12天发布会的开场即是“炸场级”更新——o1完全版。相比此前的预览版本&#x…

使用Kubernetes部署MySQL+WordPress

目录 前提条件 部署MySQL和WordPress 编写yaml文件 应用yaml文件 存在问题及解决方案 创建PV(持久化卷) 创建一个PVC(持久化卷声明) 部署添加PVC 查看PV对应的主机存储 删除资源 查看资源 删除deployment和service 查看主机数据 删除PVC和PV 删除主机数据 前提条…

RabbitMQ中的异步Confirm模式:提升消息可靠性的利器

在现代分布式系统中&#xff0c;消息队列&#xff08;Message Queue&#xff09;扮演着至关重要的角色&#xff0c;它能够解耦系统组件、提高系统的可扩展性和可靠性。RabbitMQ作为一款广泛使用的消息队列中间件&#xff0c;提供了多种机制来确保消息的可靠传递。其中&#xff…

sentinel限流+其他

quick-start | Sentinel sentinel 作用 限流 熔断降级 1&#xff0c;限制什么 QPS 并发线程数 2&#xff0c;限制什么 资源&#xff0c;什么资源 服务&#xff0c;方法&#xff0c;接口&#xff0c;或者一段代码 3&#xff0c;实现方式 配置规则 注解 其他 Java常见5种限流…

Ubuntu 中安装 RabbitMQ 教程

简介 RabbitMq作为一款消息队列产品&#xff0c;它由Erlang语言开发&#xff0c;实现AMQP&#xff08;高级消息队列协议&#xff09;的开源消息中间件。 应用场景 异步处理 场景说明&#xff1a;用户注册后&#xff0c;注册信息写入数据库&#xff0c;再发邮件、短信通知。 …

Spark生态圈

Spark 主要用于替代Hadoop中的 MapReduce 计算模型。存储依然可以使用 HDFS&#xff0c;但是中间结果可以存放在内存中&#xff1b;调度可以使用 Spark 内置的&#xff0c;也可以使用更成熟的调度系统 YARN 等。 Spark有完善的生态圈&#xff1a; Spark Core&#xff1a;实现了…

AT24C02学习笔记

看手册&#xff1a; AT24Cxx xx代表能写入xxK bit(xx K)/8 byte 内部写周期很关键&#xff0c;代表每一次页写或字节写结束后时间要大于5ms&#xff08;延时5ms确保完成写周期&#xff09;&#xff0c;否则时序会出错。 页写&#xff1a;型不同号每一页可能写入不同大小的…

119.【C语言】数据结构之快速排序(调用库函数)

目录 1.C语言快速排序的库函数 1.使用qsort函数前先包含头文件 2.qsort的四个参数 3.qsort函数使用 对int类型的数据排序 运行结果 对char类型的数据排序 运行结果 对浮点型数据排序 运行结果 2.题外话:函数名的本质 1.C语言快速排序的库函数 cplusplus网的介绍 ht…

五模型对比!Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量时间序列预测

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 光伏功率预测&#xff01;五模型对比&#xff01;Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量时间序列预测(Matlab2023b 多输入单输出) 1.程序已经调试好&#xff0c;替换数据集后&#xff0c;仅运…

利用Dockerfile构建自定义镜像

当一个系统开发完成&#xff0c;需要将系统打包为一个镜像文件&#xff0c;让docker能够运行该镜像&#xff0c;成为一个可以被访问的容器。 上述操作可以通过自定义镜像的方式来实现&#xff0c;本文章基于VMware虚拟机中安装的Centos7操作系统来完成。前面的操作步骤&#x…

喜报 | 擎创科技入围上海市优秀信创解决方案

近日&#xff0c;由上海市经信委组织的“2024年上海市优秀信创解决方案”征集遴选活动圆满落幕&#xff0c;擎创科技凭借实践经验优秀的《擎创夏洛克智能预警与应急处置解决方案》成功入选“2024年上海市优秀信创解决方案”名单。 为激发创新活力&#xff0c;发挥标杆作用&…

基于aspose.words组件的word bytes转pdf bytes,去除水印和解决linux中文乱码问题

详情见 https://preferdoor.top/archives/ji-yu-aspose.wordszu-jian-de-word-byteszhuan-pdf-bytes

快速排序学习优化

首先&#xff0c;上图。 ‘’’ cpp int partSort(int *a ,int left,int right) {int keyi left; //做左侧基准while(left<right){while(left<right && a[right]>a[keyi]){right--;}while(left<right && a[left]<a[keyi]){left;}swap(a[left…

搭建vue项目

一、环境准备 1、安装node node官网&#xff1a;https://nodejs.org/zh-cn 1.1、打开官网&#xff0c;选择“下载”。 1.2、选择版本号&#xff0c;选择系统&#xff0c;根据需要自行选择&#xff0c;上面是命令安装方式&#xff0c;下载是下载安装包。 1.3、检查node安装…