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

news/2024/11/2 11:03:08/

精品专题:

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@AllArgsConstructorpublic 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)@ResponseBodypublic String save(@RequestBody Hero hero){System.out.println("hero save..." + hero);return "{'message':'hero save'}";}@RequestMapping(value = "/heros/{id}",method = RequestMethod.DELETE)@ResponseBodypublic String delete(@PathVariable Integer id){System.out.println("hero delete..." + id);return "{'message':'hero delete'}";}@RequestMapping(value = "/heros",method = RequestMethod.PUT)@ResponseBodypublic String update(@RequestBody Hero hero){System.out.println("hero update..." +hero);return "{'message':'hero update'}";}@RequestMapping(value = "/heros/{id}",method = RequestMethod.GET)@ResponseBodypublic String getById(@PathVariable Integer id){System.out.println("hero getById..." + id);return "{'message':'hero getById'}";}@RequestMapping(value = "/heros",method = RequestMethod.GET)@ResponseBodypublic 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@PostMappingpublic String save(@RequestBody Hero hero){System.out.println("hero save..." + hero);return "{'message':'hero save'}";}//    @RequestMapping(value = "/heros",method = RequestMethod.PUT)
//    @ResponseBody@PutMappingpublic 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@GetMappingpublic 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();// 获取ipString 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 mapperPUBLIC "-//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 {@AutowiredHeroService service;@GetMappingpublic 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 {@Autowiredprivate HeroDao dao;@Overridepublic 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.ppmy.cn/news/1543847.html

相关文章

聊一聊Elasticsearch的基本原理与形成机制

1、搜索引擎的基本原理 通常搜索引擎包括&#xff1a;数据采集、文本分析、索引存储、搜索等模块&#xff0c;它们之间的协作流程如下图&#xff1a; 数据采集模块负责采集需要搜索的数据源。 文本分析模块是将结构化数据中的长文本切分成有实际意义的词&#xff0c;这样用户…

EMR Serverless Spark:一站式全托管湖仓分析利器

本文根据2024云栖大会实录整理而成&#xff0c;演讲信息如下&#xff1a; 演讲人&#xff1a; 李钰&#xff08;绝顶&#xff09; | 阿里云智能集团资深技术专家&#xff0c;阿里云 EMR 团队负责人 活动&#xff1a; 2024 云栖大会 AI - 开源大数据专场 数据平台技术演变 …

【React】配置图标和题目

图标和题目这些基本配置都是在 public/index.html&#xff0c;直接修改 link 中的 favicon.ico 就是修改图标&#xff1b;title 标签就是题目修改。 <!DOCTYPE html> <html lang"en"><head><meta charset"utf-8" /><link rel&…

stm32——GPIO开发

目录 1、什么是GPIO 2、GPIO的作用 3、GPIO的基本结构 4、GPIO引脚的基本结构 5、GPIO端口模式的配置 1. 输入浮空&#xff08;Input Floating&#xff09; 2. 输入上拉&#xff08;Input Pull-Up&#xff09; 3. 输入下拉&#xff08;Input Pull-Down&#xff09; 4. …

什么是Web3D交互展示?有什么优势?

在智能互联网的新纪元&#xff0c;传统的图片、文字及视频展示方式&#xff0c;因缺乏互动性&#xff0c;正逐渐失去其宣传的吸引力与优势。而Web3D交互展示技术的崛起&#xff0c;为众多品牌与企业开辟了新的展示路径&#xff0c;使得线上产品展示变得生动立体、交互性强&…

Apache paimon表管理

表管理 2.9.4.1 管理快照 1)快照过期 Paimon Writer每次提交都会生成一个或两个快照。每个快照可能会添加一些新的数据文件或将一些旧的数据文件标记为已删除。然而,标记的数据文件并没有真正被删除,因为Paimon还支持时间旅行到更早的快照。它们仅在快照过期时被删除。 …

vue-echarts使用

vue-echarts使用 排名柱状图示例代码 汇总示例代码 平均时效示例代码 全图 排名柱状图 示例 代码 // 排名趋势<!-- 排名数据趋势图 --><div class"rank"><div class"rank_title"><div class"rank_title_left"><spa…

第十讲 MySQL为什么有时候会选错索引?

第十讲 MySQL为什么有时候会选错索引&#xff1f; 一、问题引入 在 MySQL 中&#xff0c;索引选择由优化器负责&#xff0c;其目标是以最小代价执行语句&#xff0c;但有时会选错索引&#xff0c;导致执行速度变慢。 二、案例分析 案例一 建表与数据插入 创建表t&#xff…