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

ops/2024/11/3 0:00:24/

精品专题:

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/ops/130553.html

相关文章

牛客周赛 Round 65

文章目录 超市思路&#xff1a;Solved&#xff1a; 雨幕思路&#xff1a;Solved&#xff1a; 闺蜜思路&#xff1a;Solved&#xff1a; 医生思路&#xff1a;Solved&#xff1a; 降温&#xff08;easy&#xff09;思路&#xff1a;Solved&#xff1a; F-降温&#xff08;hard&a…

【测试平台】打包 子节点ios环境配置

主要记录如何配置ios打包机环境&#xff0c;ios环境相对来说比较简单的&#xff0c;研发配置好证书可以本地打包&#xff0c;接入流程比较简单了。 打包机系统升级 1.升级mac OS系统 一般升级好几个小时&#xff0c;可以晚上下载好 2.下载xcode并安装 Appstroe 下载安装xco…

数据结构之链式结构二叉树的实现(初级版)

本文内容将主会多次用到函数递归知识&#xff01;&#xff01;&#xff01; 本节内容需要借助画图才能更好理解&#xff01;&#xff01;&#xff01; 和往常一样&#xff0c;还是创建三个文件 这是tree.h #pragma once #include<stdio.h> #include<stdlib.h> …

学习记录:js算法(八十二):组合总和

文章目录 组合总和思路一思路二思路三 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。 candidate…

Docker:容器化和虚拟化

虚拟化 虚拟化是一种资源管理技术&#xff0c;它将计算机的各种实体资源&#xff08;如CPU、内存、磁盘空间、网络适配器等&#xff09;予以抽象、转换后呈现出来&#xff0c;并可供分割、组合为一个或多个电脑配置环境。这些资源的新虚拟部分是不受现有资源的架设方式、地域或…

git常见指令

概念 远程仓库和本地仓库 常用指令&#xff1a; ls/ll查看当前目录cat查看文件内容touch创建文件vivi编辑器 备注&#xff1a; git GUI&#xff1a;是git提供的图形化工具 GIT Bash&#xff1a;Git提供的命令行工具 在安装GIT后要配置用户和账号&#xff01; 配置用户信息 …

HTTP服务器测试与优化

目录 1 搭建一个基础的HTTP服务器 2 长连接测试 3 测试错误报文的处理 4 测试业务处理耗时超过超时时间的处理 5 测试同时收到多条正常请求 6 大文件传输测试 7 压力测试 1 搭建一个基础的HTTP服务器 在这个部分&#xff0c;我们需要搭建一个最简单的HTTP服务器&#xf…

Java的包、final关键字以及代码块

Java的包、final关键字以及代码块 一、包 包的作用 &#xff1a; ​ 包就是文件夹&#xff0c;用来管理各种不同功能的Java类 包名的书写规则&#xff1a; ​ 公司域名反写 包的作用&#xff0c;需要全部英文小写&#xff0c;见名知意 什么是全类名&#xff1a; ​ 包名…