当前位置: 首页 > article >正文

【SSM详细教程】-15-Spring Restful风格【无敌详细】

精品专题:

01.《C语言从不挂科到高绩点》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12753294.html?spm=1001.2014.3001.5482

02. 《SpringBoot详细教程》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12789841.html?spm=1001.2014.3001.5482

03.《SpringBoot电脑商城项目》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12752883.html?spm=1001.2014.3001.5482

04.《VUE3.0 核心教程》课程详细笔记 

https://blog.csdn.net/yueyehuguang/category_12769996.html?spm=1001.2014.3001.5482

05. 《SSM详细教程》课程详细笔记 

https://blog.csdn.net/yueyehuguang/category_12806942.html?spm=1001.2014.3001.5482

================================

||     持续分享系列教程,关注一下不迷路 ||

||                视频教程:墨轩大楼               ||

================================

📚 一、Rest风格简介

        Rest风格是一种表现形式状态转换,它是一种软件架构风格,当我们想表示一个网络资源的时候,可以使用两种方式:

  • 传统风格资源描述形式:

http://localhost/user/getById?id=1 查询id为1的用户信息

http://localhost/user/saveUser 保存用户信息

  • Rest风格描述形式

http://localhost/user/1

http://localhost/user

       传统方式一般是一个请求对应一种操作,这样做不仅麻烦,也不安全,因为会程序的人读取了请求URL地址,就大概知道该URL实现的是一个什么样的操作。

        查看REST风格的描述,你会发现请求地址变的简单了,并且如果只看请求URL并不容易猜出该URL的具体功能。

        REST的优点:隐藏资源的访问行为,无法通过地址得知对资源是何种操作,并且书写简单。

        但是随之而来的就会有一个问题,一个相同的URL地址,即可以是新增也可以是修改或者查询,那么到底该如何区分请求到底是什么操作呢?

        REST风格访问资源时使用行为动作区分对资源进行了何种操作:

http://localhost/users 查询全部用户信息 GET(查询)

http://localhost/users/1 查询指定用户信息 GET(查询)

http://localhost/users 添加用户信息 POST(新增/保存)

http://localhost/users 修改用户信息 PUT(修改/更新)

http://localhost/users/1 删除用户信息 DELETE(删除)

        请求方式比较多,但是比较常用的有4种,分别是 GET、POST、PUT、DELETE,不同的请求方式代表不同的操作类型:

发送GET请求时做查询操作

发送POST请求时做新增操作

发送PUT请求时做修改操作

发送DELETE请求时做删除

        但是需要注意的是,上面的内容仅仅是约定而不是规则,约定是可以打破的,所以称为REST规范而不是REST规则,这就好比变量的命名规范和命名规则一样。

        REST提供了对应的架构方式,按照这种架构设计项目可以降低开发的复杂性,提高系统的可伸缩性。REST种规定GET/POST/PUT/DELETE针对的是查询/新增/修改/删除。

📚 二、Restful 入门案例

通常以REST风格对资源进行访问,我们称为Restful,下面我们以一个案例详细了解一下Restful。

🌾 新建项目,并在pom.xml中导入依赖

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.2.10.RELEASE</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.9.0</version>
</dependency>
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>RELEASE</version>
  <scope>compile</scope>
</dependency>

🌾 在项目的resources目录中新建springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">

    <context:component-scan base-package="com.moxuan.mvc_restful.controller"></context:component-scan>
    <mvc:annotation-driven/>
    <!--    配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--        在/WEB-INF/view/ 目录下,寻找后缀为.jsp的文件-->
        <property name="prefix" value="/WEB-INF/view/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
            </list>
        </property>
    </bean>


</beans>

🌾 配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <servlet>
        <servlet-name>restful</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>restful</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>code</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>code</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

🌾 实体类Hero

package com.moxuan.mvc_restful.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Hero {
        private Integer id;
        private String name;
        private int level;
        private String job;
    }

🌾 控制器Controller类

package com.moxuan.mvc_restful.controller;

import com.moxuan.mvc_restful.pojo.Hero;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
public class HeroController {
    @RequestMapping(value = "/heros",method = RequestMethod.POST)
    @ResponseBody
    public String save(@RequestBody Hero hero){
        System.out.println("hero save..." + hero);
        return "{'message':'hero save'}";
    }

    @RequestMapping(value = "/heros/{id}",method = RequestMethod.DELETE)
    @ResponseBody
    public String delete(@PathVariable Integer id){
        System.out.println("hero delete..." + id);
        return "{'message':'hero delete'}";
    }

    @RequestMapping(value = "/heros",method = RequestMethod.PUT)
    @ResponseBody
    public String update(@RequestBody Hero hero){
        System.out.println("hero update..." +hero);
        return "{'message':'hero update'}";
    }

    @RequestMapping(value = "/heros/{id}",method = RequestMethod.GET)
    @ResponseBody
    public String getById(@PathVariable Integer id){
        System.out.println("hero getById..." + id);
        return "{'message':'hero getById'}";
    }

    @RequestMapping(value = "/heros",method = RequestMethod.GET)
    @ResponseBody
    public String getAll(){
        System.out.println("hero getAll...");
        return "{'message':'hero getAll'}";
    }

}

✍️ 【笔 记】 关于@PathVariable,它的作用是绑定路径参数与处理器方法中的参数间的关系,要求路径参数名与方法中的参数名一样。

❓ 【面试题】@RequestBody、@RequestParam 、@PathVariable 都是用来接收参数的,它们之间的区别和应用分别是什么?

区别:

@RequestParam 用于接收url地址传参或表单传参,比如:/getUserById?id=1, 中的id值。

@RequestBody 用于接收Json格式的数据。

@PathVariable 用于接收路径参数,使用{参数名}描述路径参数,比如:/users/{id},中的id值

应用:

后期开发中,发送请求参数超过1个时,建议使用json格式,@RequestBody运用的会比较广泛。

如果发送非json格式数据,选用@RequestParam接收请求参数。

采用RESTful进行开发,当参数数量较少时,例如1个,可以采用@PathVariable接收请求路径变量,通常用于传递id值。

🌾打开PostMan进行测试

1️⃣ 测试新增数据

👀 首先设置content-type为application/json

👀 然后设置json格式的数据,然后以post方式发送请求:

⚠️ 注意: 新增操作,需要发送Post请求

👀 运行结果:

2️⃣ 测试修改数据

👀 修改请求方式为PUT,发送请求

👀 测试结果,如下图所示:

3️⃣ 测试查询数据

👀 修改请求方式为GET,发送请求

请求后面不带数据,表示查询所有的数据,测试结果:

👀 请求方式为GET,在地址后面添加1

请求后面携带的有一个1,表示查询id为1的数据,测试结果:

4️⃣ 测试删除数据

👀 修改请求方式为DELETE发送请求

测试结果如下:

📚 RESTful 快速开发

🌾 问题描述

前面我们使用了restful,可以看出避免了一些请求的外显,而且现在发送请求也相对之前来说简易一些。但是目前任然还存在一些麻烦点,如下图所示:

每个方法的@RequestMapping注解中都定义了访问路径 /heros, 重复性太高了。

每个方法的@RequestMapping注解中都要使用method属性定义请求方式,重复性太高了。

每个方法响应json都需要加上@ResponseBody注解,重复性太高。

🌾 解决方案

  1. 采用前面讲过的请求路径映射,在Controller类的上方统一加上@RequestMapping
  2. 使用@RestController 代替@Controller注解,@RestController=@Controller + @ResponseBody.
  3. 分别使用@PostMapping、@GetMapping、@PutMapping、@DeleteMapping 来替换@RequestMapping中的method设定

👇👇👇且看下面代码

package com.moxuan.mvc_restful.controller;

import com.moxuan.mvc_restful.pojo.Hero;
import org.springframework.web.bind.annotation.*;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: moxuan
 * @Date: 2023/08
 * @Description:
 */
@RestController
@RequestMapping("/heros")
public class HeroController {
//    @RequestMapping(value = "/heros",method = RequestMethod.POST)
//    @ResponseBody
    @PostMapping
    public String save(@RequestBody Hero hero){
        System.out.println("hero save..." + hero);
        return "{'message':'hero save'}";
    }

//    @RequestMapping(value = "/heros",method = RequestMethod.PUT)
//    @ResponseBody
    @PutMapping
    public String update(@RequestBody Hero hero){
        System.out.println("hero update..." +hero);
        return "{'message':'hero update'}";
    }

//    @RequestMapping(value = "/heros/{id}",method = RequestMethod.DELETE)
//    @ResponseBody
    @DeleteMapping("/{id}")
    public String delete(@PathVariable Integer id){
        System.out.println("hero delete..." + id);
        return "{'message':'hero delete'}";
    }

//    @RequestMapping(value = "/heros/{id}",method = RequestMethod.GET)
//    @ResponseBody
    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id){
        System.out.println("hero getById..." + id);
        return "{'message':'hero getById'}";
    }

//    @RequestMapping(value = "/heros",method = RequestMethod.GET)
//    @ResponseBody
    @GetMapping
    public String getAll(){
        System.out.println("hero getAll...");
        return "{'message':'hero getAll'}";
    }

}

✍️ 【笔记】

@RestController

基于SpringMVC的RESTful开发控制器类,设置当前控制器类为RESTful风格,等同于@Controller与@ResponseBody两个注解的组合。

@GetMapping、@PostMapping、 @PutMapping 、 @DeleteMapping

设置当前控制器方法请求访问路径与请求动作,每一种对应一个请求动作,比如@GetMapping对应GET请求。

🌲 综合案例

使用SSM整合RESTful风格实现对英雄数据的增删改查,现在很多新项目都采用前后端分离的方式进行开发,前面在讲SSM整合的时候,我们已经使用过一般风格的方式整合了,这里我们采用前后端分离的方式整合RESTful风格。

🌿 数据表

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `hero`
-- ----------------------------
DROP TABLE IF EXISTS `hero`;
CREATE TABLE `hero` (
  `id` int NOT NULL AUTO_INCREMENT,
  `hname` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
  `job` varchar(255) DEFAULT NULL,
  `level` int DEFAULT NULL,
  `sex` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb3;

-- ----------------------------
-- Records of hero
-- ----------------------------
INSERT INTO `hero` VALUES ('1', '夏侯惇', '战士', '2', '男');
INSERT INTO `hero` VALUES ('3', '甄姬', '法师', '2', '女');
INSERT INTO `hero` VALUES ('4', '安琪拉', '法师', '3', '女');
INSERT INTO `hero` VALUES ('5', '廉颇', '辅助', '1', '男');
INSERT INTO `hero` VALUES ('6', '张飞', '辅助', '1', '男');
INSERT INTO `hero` VALUES ('7', '后羿', '射手', '3', '男');
INSERT INTO `hero` VALUES ('8', '虞姬', '射手', '3', '女');
INSERT INTO `hero` VALUES ('9', '阿珂', '刺客', '3', '女');
INSERT INTO `hero` VALUES ('10', '孙悟空', '刺客', '3', '男');
INSERT INTO `hero` VALUES ('12', '王昭君', '法师', '3', '女');
INSERT INTO `hero` VALUES ('13', '王昭君', '法师', '3', '女');

🌿 搭建项目环境

🍁创建项目
  • 按照下图所示建立项目结构,并导入配置文件,配置文件在本文档后续内容中获取:

  • 导入SSM项目整合所需的依赖
<dependencies>
  <!--Spring所需Jar-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <!--spring集成Junit-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>${spring.version}</version>
    <scope>provided</scope>
  </dependency>
  <!--Log4j所需Jar-->
  <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
  </dependency>
  <!--AOP所需Jar-->
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.10</version>
  </dependency>
  <dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.8.10</version>
  </dependency>
  <!--Servlet所需Jar-->
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
  </dependency>
  <!--SpringMVC依赖-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
  </dependency>
  <!--Mybatis依赖-->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.2.2</version>
  </dependency>
  <!--Spring和Mybatis集成插件-->
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.2.2</version>
  </dependency>
  <!--Mysql连接连接驱动-->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.25</version>
  </dependency>
  <!--数据源JDBC、C3P0、Druid-->
  <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version>
  </dependency>
  <!-- JSTL标签类 -->
  <dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
  </dependency>
  <!--可添加-->
  <!-- 上传组件包 -->
  <dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
  </dependency>
  <dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
  </dependency>
  <dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.9</version>
  </dependency>

  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.10.2</version>
  </dependency>
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.10.2</version>
  </dependency>
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.10.2</version>
  </dependency>
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.36</version>
  </dependency>
  <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.7</version>
  </dependency>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>RELEASE</version>
    <scope>compile</scope>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.29</version>
  </dependency>
</dependencies>
  • 在resources中添加日志相关的配置文件log4j.properties
#定义LOG输出级别
log4j.rootLogger=INFO,Console,File
#定义日志输出目的地为控制台
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.Target=System.out
#可以灵活地指定日志输出格式,下面一行是指定具体的格式
log4j.appender.Console.layout = org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=[%c] - %m%n

#文件大小到达指定尺寸的时候产生一个新的文件
log4j.appender.File = org.apache.log4j.RollingFileAppender
#指定输出目录(需要配一个绝对路径)
log4j.appender.File.File = c:/logs/ssm.log
#定义文件最大大小
log4j.appender.File.MaxFileSize = 10MB
# 输出所以日志,如果换成DEBUG表示输出DEBUG以上级别日志
log4j.appender.File.Threshold = ALL
log4j.appender.File.layout = org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern =[%p] [%d{yyyy-MM-dd HH\:mm\:ss}][%c]%m%n
🍁日志组件
  • 在config包中添加AOP日志切面ServiceLogAspect.java,代码如下:
package com.example.SSM_restful.config;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Date;


@Component
@Aspect
public class ServiceLogAspect {
    // 日志记录员
    private static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);

    @Pointcut("execution(* com.example.SSM_restful.service.*.*(..))")
    public void pointcut(){

    }

    /**
     * 前置通知
     * @param joinPoint
     */
    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        // 用户[IP 地址], 在某个时间访问了 [com.moxuan.SSM.service.xxx]
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return ;
        }
        // 获取请求
        HttpServletRequest request = attributes.getRequest();
        // 获取ip
        String ip = request.getRemoteHost();
        // 获取系统当前时间
        String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        // 获取执行的方法
        String target = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        // 记录日志
        logger.info(String.format("用户[%s], 在[%s], 访问了[%s].", ip, time, target));
    }

}

🌿 创建实体类

在entity包中新建实体类Hero,代码如下:

package com.example.SSM_restful.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Hero {
    private Integer id;
    private String hname;
    private String job;
    private Integer level;
    private String sex;
}

🌿 添加映射器

在dao包中新建HeroDao接口,作为映射器,代码如下:

package com.example.SSM_restful.dao;

@Repository
public interface HeroDao {
   
}

在resources目录下的mappers中新建数据库映射文件Hero.xml,代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 此处的namespace需要对应上dao包中的数据操作接口-->
<mapper namespace="com.example.SSM_restful.dao.HeroDao">

</mapper>

🌿 添加配置文件

🍁Mybatis相关配置

在resources目录下新建一个mysql.properties,添加数据源相关配置,代码如下:

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/study?useUnicode=true&characterEncoding=utf-8
username=root
password=123456
#定义初始连接数
initialSize=0
#定义最大连接数
maxActive=20
#定义最小空闲
minIdle=1
#定义最长等待时间
maxWait=60000

在resources目录中新建一个spring-mybatis.xml,配置数据源以及mybatis相关的配置,代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:utils="http://www.springframework.org/schema/util" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 自动扫描的路径-->
    <context:component-scan base-package="com.example.SSM_restful"></context:component-scan>
    <!-- 引入配置文件
    classpath:只会到你指定的class路径中查找找文件;
    -->
    <utils:properties location="classpath*:mysql.properties" id="mysql"></utils:properties>

    <!-- 配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <!-- 配置数据库链接基本信息-->
        <property name="url" value="#{mysql.url}" />
        <property name="driverClassName" value="#{mysql.driver}"/>
        <property name="username" value="#{mysql.username}" />
        <property name="password" value="#{mysql.password}" />
        <!-- 初始化连接大小-->
        <property name="initialSize" value="#{mysql.initialSize}"/>
        <!-- 连接池最大数量-->
        <property name="maxActive" value="#{mysql.maxActive}"/>
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="#{mysql.minIdle}"/>
    </bean>

    <!-- Mapping 文件-->
    <!-- Spring 和mybatis完美整合,不需要mybatis的配置文件-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- 配置实体类的别名-->
        <property name="typeAliasesPackage" value="com.example.SSM_restful.entity"/>
        <!-- 自动扫描mapping.xml映射文件-->
        <property name="mapperLocations" value="classpath:mappers/*.xml"/>
    </bean>

    <!-- Dao 接口-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 配置 Dao 接口所在的包名,Spring会自动查找其下的类-->
        <property name="basePackage" value="com.example.SSM_restful.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>

    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager" />
    <aop:config>
        <aop:pointcut expression="execution(* com.example.SSM_restful.service.*.*(..))" id="productServiceMethods" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="productServiceMethods" />
    </aop:config>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="delete*" propagation="REQUIRED" />
            <tx:method name="modify*" propagation="REQUIRED" />
            <tx:method name="insert*" propagation="REQUIRED" />
            <tx:method name="remove*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="find*" propagation="REQUIRED" read-only="true" />
            <tx:method name="get*" propagation="REQUIRED" read-only="true" />
            <tx:method name="*" />
        </tx:attributes>
    </tx:advice>
</beans>

🛎️注意:需要将配置文件中的一些路径修改成你自己项目的实际路径

  • 自动扫描的路径
<context:component-scan base-package="com.example.SSM_restful"></context:component-scan>
  • 数据源配置文件路径
<utils:properties location="classpath*:mysql.properties" id="mysql"></utils:properties>
  • 实体类路径以及映射文件路径
<!-- 配置实体类的别名-->
<property name="typeAliasesPackage" value="com.example.SSM_restful.entity"/>
<!-- 自动扫描mapping.xml映射文件-->
<property name="mapperLocations" value="classpath:mappers/*.xml"/>
  • 自动扫描dao映射器接口的路径
 <!-- 配置 Dao 接口所在的包名,Spring会自动查找其下的类-->
<property name="basePackage" value="com.example.SSM_restful.dao"/>
  • 事务管理中,service业务层的路径
<aop:pointcut expression="execution(* com.example.SSM_restful.service.*.*(..))" id="productServiceMethods" />

🍁 添加springMvc相关配置

在resources目录下,新建spring-mvc.xml,添加关于web相关的配置,代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:anotation="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--自动扫描包路径,扫描@Controller控制器类-->
    <context:component-scan base-package="com.example.SSM_restful"/>
    <!-- 开启mvc注解扫描-->
    <mvc:annotation-driven/>

    <mvc:default-servlet-handler/>
    <!-- 开启对aop注解的支持-->
    <aop:aspectj-autoproxy/>
    <!--
        JSON 转换器
    -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
                <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
            </list>
        </property>
    </bean>

    <!-- 3.x version -->
    <!-- HandlerMapping 托管映射处理器 RequestMappingHandlerMapping -->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
    <!-- HandlerAdapter 托管适配处理器 RequestMappingHandlerAdapter-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
    <!-- 避免IE执行Ajax时,返回JSON出现下载文件-->
    <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="supportedMediaTypes">
            <list>
<!--                防止后端返回json对象中文乱码-->
                <value>application/json;charset=utf-8</value>
                <value>text/html;charset=utf-8</value>
                <!-- application 可以在任意 form 表单里面 enctype 属性默认找到 -->
                <value>application/x-www-form-urlencoded</value>
            </list>
        </property>
    </bean>

    <!-- ViewResolver 托管视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>

    </bean>

    <!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 默认编码 -->
        <property name="defaultEncoding" value="utf-8"/>
        <!-- 文件大小最大值 -->
        <property name="maxUploadSize" value="10485760000"/>
        <!-- 内存中的最大值 -->
        <property name="maxInMemorySize" value="40960"/>
    </bean>

</beans>

🛎️ 配置文件中需要注意的点:

  • 开启自动扫描的包路径一定要是自己项目的实际路径
  • Restful前后端分离,涉及了频繁的json访问以及json转换,我们添加了json相关的配置,可以帮我们自动进行转换。
  • 视图解析器,由于是前后端分离,我们给前端只返回数据,可以不配置
  • 文件上传的配置,本案例中不涉及,也可以不配置。

🍁 web.xml配置

在web.xml中配置DispatchcerServlet以及相关过滤器以及监听器等等,代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mybatis.xml</param-value>
    </context-param>

    <!-- 配置编码过滤器-->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <async-supported>true</async-supported>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- Spring 监听器-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- 防止Spring内存溢出监听器-->
    <listener>
        <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    </listener>
    <!--  配置DispatcherServlet  -->
    <servlet>
        <servlet-name>SSM</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>SSM</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

🌿 查询英雄列表

在entity包中新建一个Result类,用来封装后端给前端传输的数据,代码如下:

package com.example.SSM_restful.entity;

import lombok.Data;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: moxuan
 * @Date: 2023/08
 * @Description: 对返回数据进行统一封装
 */
@Data
public class Result {

    private int code;// 状态码
    private String msg;// 消息
    private Object data;// 数据源

    public static final int SUCCESS_CODE=200;
    public static final int ERROR_CODE=-1;
    public  static final String SUCCESS_MSG="请求成功";
    public  static final String ERROR_MSG="请求失败";

    public static Result success(){
        Result result = new Result();
        result.setCode(SUCCESS_CODE);
        result.setMsg(SUCCESS_MSG);
        return result;
    }
    public static Result error(){
        Result result = new Result();
        result.setCode(ERROR_CODE);
        result.setMsg(ERROR_MSG);
        return result;
    }


    public static Result sendResult(int code, String msg,Object obj){
        Result result =  new Result();
        result.setData(obj);
        result.setMsg(msg);
        result.setCode(code);
        return result;
    }

    public static Result sendResult(int code, String msg) {
        Result result =  new Result();
        result.setMsg(msg);
        result.setCode(code);
        return result;
    }
}

在controller包中新增HeroController,添加查询的方法,代码如下:

package com.example.SSM_restful.controller;

import com.example.SSM_restful.entity.Hero;
import com.example.SSM_restful.entity.Result;
import com.example.SSM_restful.service.HeroService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;


import java.util.List;

@RestController
@RequestMapping("/hero")
@CrossOrigin("*") // 解决前后端分离项目跨域问题,
public class HeroController {

    @Autowired
    HeroService service;

    @GetMapping
    public Result heros(){
        Result result = service.getAllHeros();
        System.out.println(result);

        return result;
    }

}

注意:

  • 查询请求使用的是@GetMapping
  • 如果前端项目和后端项目不在同一个服务器,就会存在跨域问题,此时可以在Controller上方添加@CrossOrigin("*"),来解决跨域问题

在service包中新建HeroService接口,代码如下:

package com.example.SSM_restful.service;

import com.example.SSM_restful.entity.Hero;
import com.example.SSM_restful.entity.Result;

public interface HeroService {
    Result getAllHeros();
}

在service包中新建impl包,然后在其中新建一个HeroServiceImpl类去实现HeroService接口,代码如下:

package com.example.SSM_restful.service.impl;

import com.example.SSM_restful.dao.HeroDao;
import com.example.SSM_restful.entity.Hero;
import com.example.SSM_restful.entity.Result;
import com.example.SSM_restful.service.HeroService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class HeroServiceImpl implements HeroService {
    @Autowired
    private HeroDao dao;

    @Override
    public Result getAllHeros() {
        List<Hero> heroList = dao.findAllHeros();
        if (heroList.size()==0){
            return Result.sendResult(Result.ERROR_CODE,"未查询到数据");
        }
        return Result.sendResult(Result.SUCCESS_CODE,"操作成功",heroList);
    }
}

在HeroDao中添加查询数据的方法,findAllHeros(),代码如下:

@Select("select * from hero")
List<Hero> findAllHeros();

启动服务器,打开postman进行测试:

🌿 根据id查询数据

接下来我们来看看,如果要查询id为1的英雄数据,按照restful风格的话,我们的地址就需要使用:http://localhost:8080/hero/1

在HeroController中添加处理根据id查询数据的请求方法,在请求的@GetMapping 中添加{id},然后使用@PathVariable获取请求中的参数值,代码如下:

@GetMapping("/{id}")
public Result getHeroByID(@PathVariable int id){
    Result result = service.getHero(id);
    return result;
}

在HeroServiceImpl中实现getHero方法,代码如下:

@Override
public Result getHero(int id) {
    Hero hero = dao.findHeroById(id);
    if(hero==null){
        return Result.sendResult(Result.ERROR_CODE,"未查询到数据");
    }
    return Result.sendResult(Result.SUCCESS_CODE,"操作成功",hero);
}

在HeroDao中添加findHeroById方法,代码如下:

@Select("select * from hero where id=#{id}")
Hero findHeroById(@Param("id") int id);

打开Postman进行测试:

🌿 添加英雄数据

  • 做添加操作时,我们需要处理的请求是Post请求,我们在HeroController中添加对应的处理请求的方法,代码如下:
@PostMapping
public Result saveHero(Hero hero){
	Result result = service.saveHero(hero);
	return result;
}
  • 在业务层中,添加saveHero的实现方法,代码如下:
@Override
public Result saveHero(Hero hero) {
    int num = dao.addUser(hero);
    if(num==0){
        return Result.sendResult(Result.ERROR_CODE,"添加数据失败");
    }
    return Result.sendResult(Result.SUCCESS_CODE,"成功添加数据");
}
  • 在HeroDao中添加对应的方法,代码如下:
@Insert("insert into hero (hname,job,level,sex) values(#{h.hname},#{h.job},#{h.level},#{h.sex})")
int addUser(@Param("h") Hero hero);
  • 打开postman进行测试:

🌿修改数据

  • 做修改操作时,我们需要处理的请求是Put请求,我们在HeroController中添加对应的处理请求的方法,代码如下:
@PutMapping
public Result updateHero(Hero hero){
	Result result = service.updateHero(hero);
	return result;
}
  • 在业务层Service中添加对应的方法,代码如下:
@Override
public Result updateHero(Hero hero) {
    int num = dao.updateHero(hero);
    if(num==0){
        return Result.sendResult(Result.ERROR_CODE,"修改数据失败");
    }
    return Result.sendResult(Result.SUCCESS_CODE,"成功修改数据");
}
  • 在HeroDao中添加对应的updateHero方法,代码如下:
@Update("update hero set " +
        " hname=#{h.hname}," +
        " job=#{h.job}," +
        " level=#{h.level}," +
        " sex=#{h.sex} " +
        "where id=#{h.id}")
int updateHero(@Param("h") Hero hero);
  • 打开postman测试yH5BAAAAAAALAAAAAAOAA4AAAIMhI+py+0Po5y02qsKADs=

🌿 删除数据

  • 删除数据时,我们需要处理的请求是Delete请求,我们在HeroController中添加对应的方法,代码如下:
@DeleteMapping("/{id}")
public Result deleteHero(@PathVariable int id){
    Result result = service.deleteHero(id);
    return result;
}
  • 在业务层Service中添加对应的deleteHero方法,代码如下:
@Override
public Result deleteHero(int id) {
    int num = dao.deleteHero(id);
    if(num==0){
        return Result.sendResult(Result.ERROR_CODE,"删除数据失败");
    }
    return Result.sendResult(Result.SUCCESS_CODE,"成功删除数据");
}
  • 在HeroDao中添加deleteHero方法,代码如下:
@Delete("delete from hero where id=#{id}")
int deleteHero(@Param("id") int id);
  • 打开Postman进行测试:

至此,案例中后端部分功能接口已经完毕,前端只需按照对应的接口要求发送请求和数据即可。


http://www.kler.cn/a/372079.html

相关文章:

  • Qt使用QZipWriter和QZipReader来解压、压缩文件
  • 《战神:诸神黄昏》游戏运行时提示mss32.dll丢失怎么办?
  • 使用helm安装canal-server和canal-admin
  • .NET Framework 逐渐过时,.NET 8和 .NET 9引领未来
  • CSS中的calc函数使用
  • 探索多模态大语言模型(MLLMs)的推理能力
  • OpenCV基本操作(python开发)——(7)实现图像校正
  • ios 快捷指令扩展(Intents Extension)简单使用 swift语言
  • 北航软件工程考研难度分析!
  • 依托微信小程序,畅享校园二手交易
  • 面试宝典(五):用三个线程按顺序循环打印123三个数字,比如123123123
  • 推荐一款优秀的pdf编辑器:Ashampoo PDF Pro
  • Mac OS 搭建MySQL开发环境
  • [蓝桥杯 2015 省 A] 饮料换购
  • java装饰器设计模式
  • 【测试平台】打包 jenkins配置和jenkinsfile文件
  • 2023IKCEST第五届“一带一路”国际大数据竞赛--社交网络中多模态虚假 媒体内容核查top11
  • 在绑定 Google 邮箱的手机设备上,未收到二步验证码通知是什么原因?
  • Scala练习50题(基础入门)
  • 前端八股文第一篇
  • 法律智能助手:开源NLP系统助力法律文件高效审查与检索
  • MATLAB语音信号处理系统
  • 在 CentOS 7 上安装 Node.js 18.20.4
  • 谓语和谓语动词
  • 网站攻击,XSS攻击的类型
  • 代码随想录 | Day36 | 动态规划 :整数拆分不同的二叉搜索树