文章目录
1、项目架构
1.1、项目介绍
拉勾教育后台管理系统,是提供给拉勾教育的相关业务人员使用的一个后台管理系统, 业务人员可以在这个后台管理系统中,对课程信息、广告信息、用户信息、 权限信息等数据进行维护
在 web阶段,我们已经完成了拉勾教育后台管理系统中课程模块, 接下来将对拉勾教育后台管理系统进行升级改造,基于SSM框架来完成课程信息模块,广告信息模块,用户信息模块,权限信息模块
1.2、技术选型
1.2.1、前端技术选型
前端技术 | 说明 |
---|---|
Vue.js | 是一套用于构建用户界面的渐进式JavaScript框架 |
Element UI库 | element-ui 是饿了么前端出品的基于 Vue.js的 后台组件库,方便程序员进行页面快速布局和构建 |
node.js | 简单的说 Node.js 就是运行在服务端的 JavaScript 运行环境 |
axios | 对ajax的封装, 简单来说就是ajax技术实现了局部数据的刷新,axios实现了对ajax的封装, |
1.2.2、后端技术选型
后端技术 | 说明 |
---|---|
Web层 | 借助springmvc接收请求,进行视图跳转 |
Service层 | 借助spring进行IOC、AOP、及事务管理 |
dao层 | 借助mybatis进行数据库交互 |
1.3、项目开发环境
- 开发工具
- 后端: IDEA 2022.3
- 前端: VS code
- 数据库客户端工具: Navicat Premium
- 开发环境
- JDK 11
- Maven 3.8.6
- MySQL 5.7
2、Maven进阶使用(Maven聚合工程)
2.1、maven的依赖传递
2.1.1、什么是依赖传递
在maven中,依赖是可以传递的,假设存在三个项目,分别是项目A,项目B以及项目C。假设C依赖B,B依赖A,那么我们可以根据maven项目依赖的特征不难推出项目C也依赖A。
通过上面的图可以看到,我们的web项目直接依赖了spring-webmvc,而spring-webmvc依赖了sping-aop、spring-beans等。最终的结果就是在我们的web项目中间接依赖了spring-aop、spring-beans等。
- 依赖冲突
由于依赖传递现象的存在, spring-webmvc 依赖 spirng-beans-5.1.5,spring-aop 依赖 spring-beans-5.1.6,但是发现 spirng-beans-5.1.5 加入到了工程中,而我们希望 spring-beans-5.1.6 加入工程。这就造成了依赖冲突
2.1.2、如何解决依赖冲突
- 使用maven提供的依赖调解原则
- 第一声明者优先原则
- 路径近者优先原则
- 排除依赖
- 锁定版本
2.1.3、依赖调节原则——第一声明者优先原则
在 pom 文件中定义依赖,以先声明的依赖为准。其实就是根据坐标导入的顺序来确定最终使用哪个传递过来的依赖
最终
:这里使用的依赖是spring-beans:5.1.6,为什么不用spring-webmvc中的5.1.5呢,原因就在于spring-beans位置在前spring-webmvc在后,所以5.1.6版本优先
2.1.4、依赖调节原则——路径近者优先原则
最终
:使用的依赖是spring-beans是5.1.6版本的,因为这个是直接依赖的,spring-webmvc中的spring-beans是间接依赖的
2.1.5、排除依赖
可以使用exclusions标签将传递过来的依赖排除出去
2.1.6、版本锁定
采用直接锁定版本的方法确定依赖jar包的版本,版本锁定后则不考虑依赖的声明顺序或依赖的路径,以锁定的版本为准添加到工程中,此方法在企业开发中经常使用。
版本锁定的使用方式:
第一步:在dependencyManagement标签中锁定依赖的版本
第二步:在dependencies标签中声明需要导入的maven坐标
- 在dependencyManagement标签中锁定依赖的版本
- 在dependencies标签中声明需要导入的maven坐标
也就是你不用在搞版本了,你导入的依赖都是安装dependencyManagement设置的版本处理的
2.1.7、properties标签的使用
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.1.5.RELEASE</spring.version>
<springmvc.version>5.1.5.RELEASE</springmvc.version>
<mybatis.version>3.5.1</mybatis.version>
</properties>
<!--锁定jar版本-->
<dependencyManagement>
<dependencies>
<!-- Mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- springMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springmvc.version}</version>
</dependency>
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</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-tx</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
通过设置不同的框架的版本号,做到改一处就可以修改整个依赖的版本号,上面的代码只是约束了版本号,但是没有真正的导入依赖,导入依赖还得denpendecys那种方式去导入,不用加version了
2.2、maven聚合工程(分模块)
在现实生活中,汽车厂家进行汽车生产时,由于整个生产过程非常复杂和繁琐,工作量非常大,所以厂家都会将整个汽车的部件分开生产,最终再将生产好的部件进行组装,形成一台完整的车。
2.2.1、分模块构建maven工程分析
在企业项目开发中,由于项目规模大,业务复杂,参与的人员比较多,一般会通过合理的模块拆分将一个大型的项目拆分为N多个小模块,分别进行开发。而且拆分出的模块可以非常容易的被其他模块复用
常见的拆分方式有两种:
第一种:按照业务模块进行拆分,每个模块拆分成一个maven工程,例如将一个项目分为用户模块,订单模块,购物车模块等,每个模块对应就是一个maven工程
第二种:按照层进行拆分,例如持久层、业务层、表现层等,每个层对应就是一个maven工程
不管上面那种拆分方式,通常都会提供一个父工程,将一些公共的代码和配置提取到父工程中进行统一管理和配置。
2.2.2、maven工程的继承
在Java语言中,类之间是可以继承的,通过继承,子类就可以引用父类中非private的属性和方法。同样,在maven工程之间也可以继承,子工程继承父工程后,就可以使用在父工程中引入的依赖。继承的目的是为了消除重复代码。
2.2.3、maven工程的聚合
在maven工程的pom.xml文件中可以使用标签将其他maven工程聚合到一起,聚合的目的是为了进行统一操作
例如拆分后的maven工程有多个,如果要进行打包,就需要针对每个工程分别执行打包命令,操作起来非常繁琐。这时就可以使用标签将这些工程统一聚合到maven父工中,需要打包的时候,只需要在此工程中执行一次打包命令,其下被聚合的工程就都会被打包了。
2.2.4、maven聚合工程_搭建拉勾教育后台管理系统
工程整体结构如下:
- lagou_edu_home_parent为父工程,其余工程为子工程,都继承父工程lagou_edu_home_parent
- lagou_edu_home_parent工程将其子工程都进行了聚合
- 子工程之间存在依赖关系:
- ssm_domain依赖ssm_utils
- ssm_dao依赖ssm_domain
- ssm_service依赖ssm_dao
- ssm_web依赖ssm_service
依赖关系建立原则:当前项目中要用到那个项目的资源,那么当前项目就依赖要用到资源的项目(直接依赖和间接依赖)
2.2.5、聚合工程创建
- 先创建一个maven工程lagou_edu_home_parent
- 然后删除掉src目录
- 然后创建子工程
- 创建ssm_utils
- 创建ssm_domain
- 创建ssm_dao
- 创建ssm_service
- 创建ssm_web
- 这里还要配置一下ssm_web中的pom中的打包方式为war,并且创建webapp和对应的webx.ml文件
- 然后开始配置子工程之间的依赖关系
- ssm_domain的pom.xml中配置(ctrl+鼠标左键跳转过去就可以了)
<dependencies> <dependency> <groupId>com.lzy</groupId> <artifactId>ssm_utils</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
- ssm_dao的pom.xml配置
<dependencies> <dependency> <groupId>com.lzy</groupId> <artifactId>ssm_domain</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
- ssm_service的pom.xml配置
<dependencies> <dependency> <groupId>com.lzy</groupId> <artifactId>ssm_dao</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
- ssm_web的pom.xml配置
<dependencies> <dependency> <groupId>com.lzy</groupId> <artifactId>ssm_service</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies>
- 最后输入maven install
- 最终的项目结构
2.2.6、父工程进行依赖管理
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.1.5.RELEASE</spring.version>
<springmvc.version>5.1.5.RELEASE</springmvc.version>
<mybatis.version>3.5.1</mybatis.version>
</properties>
<!--版本锁定-->
<dependencyManagement>
<dependencies>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!--SpringMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springmvc.version}</version>
</dependency>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--mybatis坐标-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.31</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.15</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!--spring坐标-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<!--mybatis整合spring坐标-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--springMVC坐标-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.6</version>
</dependency>
<!--Beanutils-->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.3</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!--解决跨域问题所需依赖-->
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
2.2.7、子工程ssm_dao构建
首先要创建一个实体类在ssm_domain中
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Account {
private Integer id;
private String name;
private Double money;
}
- 然后创建一个mapper接口和对应的mapper.xml文件
public interface AccountMapper {
public List<Account> findAllTest();
}
<?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">
<mapper namespace="com.lzy.dao.AccountMapper">
<select id="findAllTest" resultType="account">
select * from account
</select>
</mapper>
- 创建applicationContext-dao.xml和jdbc.properties
<?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: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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--spring整合mybaits-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--配置数据源-->
<property name="dataSource" ref="dataSource"/>
<!--domain别名-->
<property name="typeAliasesPackage" value="com.lzy.domain"/>
<!--开启自动驼峰命名规则-->
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration">
<property name="mapUnderscoreToCamelCase" value="true"/>
</bean>
</property>
</bean>
<!--mapper映射扫描-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.lzy.dao"/>
</bean>
</beans>
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/db
jdbc.username=root
jdbc.password=xxxx
2.2.8、子工程ssm_serivce构建
- 创建AccountServiceImpl和接口
public interface AccountService {
public List<Account> findAllTest();
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
@Override
public List<Account> findAllTest() {
return accountMapper.findAllTest();
}
}
- 创建applicationContext-service.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: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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置IOC相关操作:开启注解扫描-->
<context:component-scan base-package="com.lzy.service"/>
<!--引入dao层中的spring配置文件-->
<import resource="classpath:applicationContext-dao.xml"/>
</beans>
2.2.9、子工程ssm_web构建
- AccountController
@RestController
@RequestMapping("/test")
public class AccountController {
@Autowired
private AccountService accountService;
@RequestMapping("/findAllTest")
public List<Account> findAllTest(){
return accountService.findAllTest();
}
}
- applicationContext-web.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: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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--引入application_service.xml-->
<import resource="classpath:applicationContext-service.xml"/>
</beans>
- spring-mvc.xml核心配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--组件扫描-->
<context:component-scan base-package="com.lzy.controller"/>
<!--mvc注解增强-->
<mvc:annotation-driven/>
<!--视图解析器-->
<!--静态资源-->
<mvc:default-servlet-handler/>
</beans>
- 前端控制器、中文乱码、spring监听器、跨域
<?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>DispatcherServlet</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>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--中文乱码-->
<filter>
<filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--配置spring监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-web.xml</param-value>
</context-param>
<!--配置跨域过滤器-->
<filter>
<filter-name>CORSFilter</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CORSFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
最后配置tomcat然后访问/test/findAllTest,说明环境没什么大问题了
3、拉勾教育后台管理系统研发
3.1、课程管理模块功能分析
在本次的项目中,首先先来完成拉勾教育后台管理系统的 课程管理模块, 课程管理模块包含了多条件查询、 图片上传、 新建&修改课程、课程状态管理、课程内容展示、回显章节对应的课程信息、新建&修改章节信息、修改章节状态、 新建&修改课时信息等接口的编写
- 实现以下功能:
- 多条件查询
- 图片上传
- 新建课程信息
- 回显课程信息
- 修改课程信息
- 课程状态管理
- 课程内容展示
- 回显章节对应的课程信息
- 新建&修改章节信息
- 修改章节状态
- 新建课时信息
3.2、课程管理模块表设计
创建数据库及表
课程表
章节表
课时表
课程媒体
3.3、课程管理模块接口实现
3.3.1、多条件课程列表查询
接口地址: http://localhost:8080/ssm-web/course/findCourseByCondition
请求方式: POST
接口描述: 分页获取课程列表数据&多条件查询
请求参数:
参数名称 | 参数说明 | in | 是否必须 | 数据类型 | schema |
---|---|---|---|---|---|
courseName | false | string | |||
status | false | integer(int32) |
请求示例:
{
"courseName": "Vue.js 3.0 核心源码解析",
"status": 1
}
响应参数:
参数名称 | 参数说明 | 类型 | schema |
---|---|---|---|
success | boolean | ||
state | integer(int32) | integer(int32) | |
message | string | ||
content | object |
响应示例:
{
"success": true,
"state": 0,
"message": "响应成功",
"content": {课程数据}
}
3.3.1.1、实体类创建
Course
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Course {
private int id;
//课程名称
private String courseName;
//课程一句话简介
private String brief;
//原价
private double price;
//原价标签
private String priceTag;
//优惠价
private double discounts;
//优惠价标签
private String discountsTag;
//课程内容markdown
private String courseDescriptionMarkDown;
//课程描述
private String courseDescription;
//课程分享图片url
private String courseImgUrl;
//是否新品
private int isNew;
//广告语
private String isNewDes;
//最后操作者
private int lastOperatorId;
//自动上架时间
private Date autoOnlineTime;
//创建时间
private Date createTime;
//更新时间
private Date updateTime;
//是否删除
private int isDel;
//总时长
private int totalDuration;
//课程列表展示图片
private String courseListImg;
//课程状态,0-草稿,1-上架
private int status;
//课程排序
private int sortNum;
//课程预览第一个字段
private String previewFirstField;
//课程预览第二个字段
private String previewSecondField;
}
ResponseResult
@AllArgsConstructor
@NoArgsConstructor
@Data
public class ResponseResult {
private Boolean success;
private Integer state;
private String message;
private Object content;
}
CourseVo:View Object表现层对象:主要用于表现层来接收参数的
@AllArgsConstructor
@NoArgsConstructor
@Data
public class CourseVo {
private String courseName;
private Integer status;
}
3.3.1.2、Dao层编写
public interface CourseMapper {
public List<Course> findCourseByConditionin(CourseVo courseVo);
}
<?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">
<mapper namespace="com.lzy.dao.CourseMapper">
<!--这里涉及到了逻辑删除,is_del != 1 -->
<select id="findCourseByConditionin" parameterType="coursevo" resultType="course">
select id, course_name, price, sort_num, status from course
<where>
<if test="courseName != null and courseName != ''">
and course_name like concat('%', #{courseName}, '%')
</if>
<if test="status != null and status != ''">
and status = #{status}
</if>
<if test="true">
and is_del != 1
</if>
</where>
</select>
</mapper>
3.3.1.3、Servicec层
public interface CourseService {
/*多条件列表查询*/
public List<Course> findCourseByConditioin(CourseVo courseVo);
}
@Service
public class CourseServiceImpl implements CourseService {
@Autowired
private CourseMapper courseMapper;
@Override
public List<Course> findCourseByConditioin(CourseVo courseVo) {
return courseMapper.findCourseByConditionin(courseVo);
}
}
3.3.1.4、Web层编写
@RestController
@RequestMapping("/course")
public class CourseController {
@Autowired
private CourseService courseService;
@RequestMapping("/findCourseByCondition")
/*这里不加这个@RequestBody注解的话,就无法把前台传过来的数据进行封装*/
public ResponseResult findCourseByCondition(@RequestBody CourseVo courseVo){
System.out.println(courseVo);
List<Course> courseByConditioin = courseService.findCourseByConditioin(courseVo);
ResponseResult responseResult = new ResponseResult(true, 200, "成功", courseByConditioin);
return responseResult;
}
}
3.3.1.5、postman接口测试
3.3.2、课程图片上传
接口地址: http://localhost:8080/ssm-web/course/courseUpload
请求方式: POST
接口描述: 课程模块图片上传
请求参数:
file=1597112871741.JPG
响应参数:
参数名称 | 参数说明 | 类型 | schema |
---|---|---|---|
success | boolean | ||
state | integer(int32) | integer(int32) | |
message | string | ||
content | object |
响应示例:
{
"success": true,
"state": 200,
"message": "响应成功",
"content": {
"fileName": "1597112871741.JPG",
"filePath": "http://localhost:8080/upload/1597112871741.JPG"
}
}
3.3.2.1、代码编写
spring-mvc.xml
<!--配置文件解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="1048576"/>
</bean>
web层
package com.lzy.service.impl;
import com.github.pagehelper.PageInfo;
import com.lzy.dao.CourseMapper;
import com.lzy.domain.Account;
import com.lzy.domain.Course;
import com.lzy.domain.CourseVo;
import com.lzy.domain.ResponseResult;
import com.lzy.service.CourseService;
import com.sun.org.apache.bcel.internal.generic.NEW;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class CourseServiceImpl implements CourseService {
@Autowired
private CourseMapper courseMapper;
@Override
public List<Course> findCourseByConditioin(CourseVo courseVo) {
return courseMapper.findCourseByConditionin(courseVo);
}
@RequestMapping("/courseUpload")
public ResponseResult fileUpload(MultipartFile file, HttpServletRequest request){
try {
/*判断文件是否为空*/
if(file.isEmpty()){
throw new RuntimeException();
}
/*获取项目部署路径*/
// 这里是获得了到webapps/ssm/的路径
String realPath = request.getServletContext().getRealPath("/");
// 这里是获得了到webapps的路径
String webappsPath = realPath.substring(0, realPath.indexOf("ssm"));
/*获取原文件名*/
String fileName = file.getOriginalFilename();
/*新的文件名*/
String newFileName = System.currentTimeMillis() + fileName.substring(fileName.lastIndexOf("."));
/*存储文件*/
String uploadPath = webappsPath + "upload\\";
File filePath = new File(uploadPath, newFileName);
/*如果目录不存在就创建目录*/
if(!filePath.getParentFile().exists()){
filePath.getParentFile().mkdirs();
System.out.println("创建目录 = " + filePath);
}
file.transferTo(filePath);
/*将文件名和文件路径返回*/
Map<String, String> map = new HashMap<>();
map.put("fileName", newFileName);
map.put("filePath", "htt://localhost:8080/upload/" + newFileName);
ResponseResult res = new ResponseResult(true, 200, "成功", map);
return res;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
3.3.2.2、postman测试
3.3.3、新建课程信息
接口地址: http://localhost:8080/ssm-web/course/saveOrUpdateCourse
请求方式: POST
接口描述: 新建课程或修改课程
请求参数:
字段 | 说明 | 类型 | 是否必需 | 备注 |
---|---|---|---|---|
id | 课程id | int | 否 | 添加操作不用携带, 修改操作必须携带ID |
courseName | 课程名称 | String | 是 | |
brief | 课程简介 | String | 是 | 一句话介绍课程 |
teacherName | 讲师名称 | String | 是 | |
description | 讲师介绍 | String | 是 | |
position | 讲师职位 | String | 是 | |
previewFirstField | 课程概述1 | String | 是 | 第一段描述 例如: 课程共15讲 |
previewSecondField | 课程概述2 | String | 是 | 第二段描述 例如: 每周五更新 |
discounts | 售卖价格 | double | 是 | 课程的售卖价格 |
price | 商品原价 | double | 是 | 课程的原销售价 |
discountsTag | 活动标签 | String | 是 | 例如: 立即抢购 |
courseImgUrl | 课程图片url | String | 是 | |
courseListImg | 封面图url | String | 是 | |
sortNum | 课程排序 | int | 是 | |
course_description_mark_down | 课程描述 | String | 是 | |
sales | 销量 | int | 是 |
请求示例
//新增
{
"courseName":"大数据云计算",
"brief":"海量大数据课程",
"teacherName":"维尼",
"description":"多年企业实战经验",
"position":"高级讲师",
"previewFirstField":"共10讲",
"previewSecondField":"每周四更新",
"discounts":66.6,
"price":88,
"discountsTag":"先到先得",
"courseImgUrl":"http://localhost:8080/upload/1596520226925.jpg",
"courseListImg":"http://localhost:8080/upload/1596520226925.jpg",
"sortNum":1,
"courseDescriptionMarkDown":"介绍当前流行大数据技术,数据技术原理,并介绍其思想,介绍大数据技术培训课程,概要介绍。",
"sales":100
}
//修改
{
"id":15,
"courseName":"全栈工程师",
"brief":"掌握多种技能,胜任前端与后端",
"teacherName":"药水哥",
"description":"多年企业实战经验",
"position":"高级讲师",
"previewFirstField":"共10讲",
"previewSecondField":"每周四更新",
"discounts":66.6,
"price":88,
"discountsTag":"先到先得",
"courseImgUrl":"http://localhost:8080/upload/1596520226925.jpg",
"courseListImg":"http://localhost:8080/upload/1596520226925.jpg",
"sortNum":1,
"courseDescriptionMarkDown":"介绍当前流行大数据技术,数据技术原理,并介绍其思想,介绍大数据技术培训课程,概要介绍。",
"sales":100
}
响应参数:
参数名称 | 参数说明 | 类型 | schema |
---|---|---|---|
success | boolean | ||
state | integer(int32) | integer(int32) | |
message | string | ||
content | object |
响应示例
{
"success": true,
"state": 200,
"message": "响应成功",
"content": null
}
需求分析
既要保存课程信息,又要保存教师的信息,并且教师的信息中存储着这门课的id值,所以这里要先保存课程信息,然后将自动生成的id作为course_id存储到教师信息中
3.3.3.1、dao层及其xml
/*新增课程信息*/
public void saveCourse(Course course);
/*新增教师信息*/
public void saveTeacher(Teacher teacher);
<!--新增课程信息-->
<insert id="saveCourse" parameterType="course">
INSERT INTO course(
course_name,
brief,
preview_first_field,
preview_second_field,
course_img_url,
course_list_img,
sort_num,
price,
discounts,
sales,
discounts_tag,
course_description_mark_down,
create_time,
update_time
) VALUES(#{courseName},#{brief},#{previewFirstField},#{previewSecondField},
#{courseImgUrl},#{courseListImg},#{sortNum},#{price},#{discounts},#{sales},
#{discountsTag},#{courseDescriptionMarkDown},#{createTime},#{updateTime});
<selectKey resultType="int" order="AFTER" keyProperty="id">
select LAST_INSERT_ID()
</selectKey>
</insert>
<!--新增讲师信息-->
<insert id="saveTeacher" parameterType="teacher">
INSERT INTO teacher(
course_id,
teacher_name,
POSITION,
description,
create_time,
update_time
) VALUES(#{courseId},#{teacherName},#{position},#{description},
#{createTime},#{updateTime});
</insert>
新知识点
:selectKey
3.3.3.2、service层
@Override
public void saveCourseOrTeacher(CourseVo courseVo) {
try {
// 封装课程信息
Course course = new Course();
ConvertUtils.register( new DateConverter(null), java.util.Date.class);
BeanUtils.copyProperties(course, courseVo);
System.out.println(course);
// 补全信息
Date date = new Date();
course.setCreateTime(date);
course.setUpdateTime(date);
// 保存课程信息
courseMapper.saveCourse(course);
// 通过那个selectKey就可以获取新插入数据的id
int id = course.getId();
// 封装讲师信息
Teacher teacher = new Teacher();
BeanUtils.copyProperties(teacher, courseVo);
// 补全信息
teacher.setCourseId(id);
teacher.setCreateTime(date);
teacher.setUpdateTime(date);
// 保存讲师信息
courseMapper.saveTeacher(teacher);
} catch (Exception e) {
e.printStackTrace();
}
}
3.3.3.3、web层
// 保存更新课程信息
@RequestMapping("/saveOrUpdateCourse")
public ResponseResult saveOrUpdateCourse(@RequestBody CourseVo courseVo){
courseService.saveCourseOrTeacher(courseVo);
ResponseResult res = new ResponseResult(true, 200, "成功", null);
return res;
}
3.3.3.4、postman测试
3.3.4、回显课程信息
- 名称: findCourseById
- 描述: 根据id查询课程信息
- URL: http://localhost:8080/ssm-web/course/findCourseById
- 请求方式: GET
- 请求实例:http://localhost:8080/ssm-web/course/findCourseById?id=16
- 请求参数
字段 | 说明 | 类型 | 是否必需 | 备注 |
---|---|---|---|---|
id | 课程id | int | 是 |
- 响应结果示例
{
"success": true,
"state": 200,
"message": "响应成功",
"content": 课程信息
}
3.3.4.1、dao层及其xml
/*回显课程信息*/
public CourseVo findCourseById(Integer id);
<select id="findCourseById" resultType="coursevo">
SELECT
course_name,
brief,
teacher_name,
POSITION,
description,
preview_first_field,
preview_second_field,
course_img_url,
course_list_img,
sort_num,
discounts,
price,
sales,
discounts_tag,
course_description_mark_down
FROM course LEFT JOIN teacher ON course.id = teacher.course_id
WHERE course.id = #{id}
</select>
3.3.4.2、service层
/*信息回显*/
public CourseVo findCourseById(Integer id);
@Override
public CourseVo findCourseById(Integer id) {
return courseMapper.findCourseById(id);
}
3.3.4.3、web层
// 回显信息
@RequestMapping("/findCourseById")
public ResponseResult findCourseById(@RequestParam Integer id){
CourseVo courseVo = courseService.findCourseById(id);
ResponseResult res = new ResponseResult(true, 200, "成功", courseVo);
return res;
}
3.3.4.4、postman测试
3.3.5、修改课程信息
3.3.5.1、dao层
/*修改课程信息*/
public void updateCourse(Course course);
/*修改讲师信息*/
public void updateTeacher(Teacher teacher);
<update id="updateCourse" parameterType="course">
update course
<trim prefix="set" suffixOverrides=",">
<if test="courseName != null and courseName != ''">
course_name = #{courseName},
</if>
<if test="brief != null and brief != ''">
brief=#{brief},
</if>
<if test="previewFirstField != null and previewFirstField != ''">
preview_first_field=#{previewFirstField},
</if>
<if test="previewSecondField != null and previewSecondField != ''">
preview_second_field=#{previewSecondField},
</if>
<if test="courseImgUrl != null and courseImgUrl != ''">
course_img_url=#{courseImgUrl},
</if>
<if test="courseListImg != null and courseListImg != ''">
course_list_img=#{courseListImg},
</if>
<if test="sortNum != null and sortNum != ''">
sort_num=#{sortNum},
</if>
<if test="price != null and price != ''">
price=#{price},
</if>
<if test="discounts != null and discounts != ''">
discounts=#{discounts},
</if>
<if test="sales != null and sales != '' or sales==0">
sales=#{sales},
</if>
<if test="discountsTag != null and discountsTag != ''">
discounts_tag=#{discountsTag},
</if>
<if test="courseDescriptionMarkDown != null and courseDescriptionMarkDown != ''">
course_description_mark_down=#{courseDescriptionMarkDown},
</if>
<if test="updateTime != null">
update_time=#{updateTime},
</if>
</trim>
<where>
<if test="id != null and id != ''">
id = #{id}
</if>
</where>
</update>
<update id="updateTeacher" parameterType="teacher">
update teacher
<trim prefix="set" suffixOverrides=",">
<if test="teacherName != null and teacherName != ''">
teacher_name = #{teacherName},
</if>
<if test="position != null and position != ''">
position = #{position},
</if>
<if test="description != null and description != ''">
description = #{description},
</if>
<if test="updateTime != null">
update_time=#{updateTime}
</if>
</trim>
<where>
<if test="courseId != null and courseId != ''">
course_id = #{courseId}
</if>
</where>
</update>
3.3.5.2、service层
/*修改课程信息*/
public void updateCourseOrTeacher(CourseVo courseVo);
@Override
public void updateCourseOrTeacher(CourseVo courseVo) {
try {
// 封装课程数据
Course course = new Course();
ConvertUtils.register(new DateConverter(null), java.util.Date.class);
BeanUtils.copyProperties(course, courseVo);
// 补充信息
Date date = new Date();
course.setUpdateTime(date);
// 更新课程
courseMapper.updateCourse(course);
// 封装讲师信息
Teacher teacher = new Teacher();
BeanUtils.copyProperties(teacher, courseVo);
// 补充信息
teacher.setCourseId(course.getId());
teacher.setUpdateTime(date);
//更新讲师信息
courseMapper.updateTeacher(teacher);
} catch (Exception e) {
e.printStackTrace();
}
}
3.3.5.3、web层
// 保存或更新课程信息
@RequestMapping("/saveOrUpdateCourse")
public ResponseResult saveOrUpdateCourse(@RequestBody CourseVo courseVo){
if (courseVo.getId() == null) {
courseService.saveCourseOrTeacher(courseVo);
ResponseResult res = new ResponseResult(true, 200, "成功", null);
return res;
}else{
courseService.updateCourseOrTeacher(courseVo);
ResponseResult res = new ResponseResult(true, 200, "成功", null);
return res;
}
}
3.3.5.4、postman测试
3.3.6、课程状态管理
接口地址: http://localhost:8080/ssm-web/course/updateCourseStatus
请求方式: GET
接口描述: 修改课程状态
请求参数:
参数名称 | 参数说明 | in | 是否必须 | 数据类型 | 备注 |
---|---|---|---|---|---|
id | 课程id | true | int | ||
status | 课程状态 | true | int | 最新的状态值 |
请求示例:
http://localhost:8080/ssm-web/course/updateCourseStatus?status=1&id=15
响应参数:
参数名称 | 参数说明 | 类型 | schema |
---|---|---|---|
success | boolean | ||
state | integer(int32) | integer(int32) | |
message | string | ||
content | object |
响应示例:
{
"success": true,
"state": 200,
"message": "响应成功",
"content": {
"status": 1
}
}
3.3.6.1、dao层
/*课程状态管理*/
public void updateCourseStatus(Course course);
<update id="updateCourseStatus" parameterType="course">
update course set status = #{status}, update_time=#{updateTime} where id = #{id}
</update>
3.3.6.2、service层
/*修改课程状态*/
public void updateCourseStatus(Integer id, Integer status);
/*修改课程信息*/
@Override
public void updateCourseStatus(Integer id, Integer status) {
// 封装课程信息
Course course = new Course();
course.setStatus(status);
course.setId(id);
course.setUpdateTime(new Date());
// 修改课程状态
courseMapper.updateCourseStatus(course);
}
3.3.6.3、web层
// 修改课程状态
@RequestMapping("/updateCourseStatus")
public ResponseResult updateCourseStatus(@RequestParam Integer id, @RequestParam Integer status){
courseService.updateCourseStatus(id, status);
HashMap<Object, Object> map = new HashMap<>();
map.put("status", status);
ResponseResult res = new ResponseResult(true, 200, "成功", map);
return res;
}
3.3.6.4、postman测试
3.3.7、课程内容展示
接口地址: http://localhost:8080/ssm-web/courseContent/findSectionAndLesson
请求方式: GET
接口描述: 根据课程ID查询章节与课时信息
请求参数:
参数名称 | 参数说明 | in | 是否必须 | 数据类型 | schema |
---|---|---|---|---|---|
courseId | 课程id | true | int |
- 请求示例
http://localhost:8080/ssm-web/courseContent/findSectionAndLesson?courseId=7
- 响应结果示例
{
"success": true,
"state": 200,
"message": "响应成功",
"content": [
{
"id": 7,
"courseId": 7,
"sectionName": "开篇词 | 从小白到文案高手,手把手教你写出爆款文案",
"description": "你好,我是兔妈!第一次见面,我用几句话简单介绍下自己",
"createTime": null,
"updateTime": null,
"isDe": 0,
"orderNum": 1,
"status": 2,
"lessonList": [
{
"id": 9,
"courseId": 7,
"sectionId": 7,
"theme": "手把手教你写出爆款文案",
"duration": 0,
"isFree": 0,
"createTime": null,
"updateTime": null,
"isDel": 0,
"orderNum": 1,
"status": 2
},
{
"id": 8,
"courseId": 7,
"sectionId": 7,
"theme": "从小白到文案高手",
"duration": 0,
"isFree": 1,
"createTime": null,
"updateTime": null,
"isDel": 0,
"orderNum": 1,
"status": 2
}
]
},
{
"id": 8,
"courseId": 7,
"sectionName": "重点内容总结",
"description": "重点内容总结",
"createTime": null,
"updateTime": null,
"isDe": 0,
"orderNum": 2,
"status": 2,
"lessonList": [
{
"id": 11,
"courseId": 7,
"sectionId": 8,
"theme": "内容总结",
"duration": 0,
"isFree": 0,
"createTime": null,
"updateTime": null,
"isDel": 0,
"orderNum": 2,
"status": 2
},
{
"id": 10,
"courseId": 7,
"sectionId": 8,
"theme": "重点内容",
"duration": 0,
"isFree": 0,
"createTime": null,
"updateTime": null,
"isDel": 0,
"orderNum": 2,
"status": 2
}
]
}
]
}
3.3.7.1、实体类
package com.lzy.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class CourseSection {
//id
private Integer id;
//课程id
private int courseId;
//章节名
private String sectionName;
//章节描述
private String description;
//创建时间
private Date createTime;
//更新时间
private Date updateTime;
//是否删除
private int isDe;
//排序
private int orderNum;
//状态
private int status;
// 课时集合
private List<CourseLesson> lessonList;
}
package com.lzy.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@AllArgsConstructor
@NoArgsConstructor
@Data
public class CourseLesson {
private Integer id;
private Integer courseId;
private Integer sectionId;
private String theme;
private Integer duration;
private Integer isFree;
private Date createTime;
private Date updateTime;
private Integer isDel;
private Integer orderNum;
private Integer status;
}
3.3.7.2、dao层
public interface CourseContentMapper {
/*查询课程下的章节与课时信息*/
public List<CourseSection> findSectionAndLessonByCourseId(Integer courseId);
}
<?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">
<mapper namespace="com.lzy.dao.CourseContentMapper">
<!--根据课程id查询课程内容-->
<select id="findSectionAndLessonByCourseId" resultMap="BaseResultMap">
select
cs.*,
cl.id lessonid,
cl.course_id,
cl.section_id,
cl.theme,
cl.duration,
cl.create_time,
cl.update_time,
cl.is_del,
cl.order_num,
cl.status,
cl.is_free
from course_section cs
left join course_lesson cl
on cl.section_id = cs.id
where cs.course_id = #{courseId}
order by cs.order_num
</select>
<!--一对多配置,一个章节下有多个课时-->
<resultMap id="BaseResultMap" type="CourseSection">
<id property="id" column="id"/>
<result property="courseId" column="course_id"/>
<result property="sectionName" column="section_name"/>
<result property="description" column="description"/>
<result property="orderNum" column="order_num"/>
<result property="status" column="status"/>
<!--使用collection,配置一对多的关系-->
<collection property="lessonList" resultMap="lessonListResultMap"/>
</resultMap>
<resultMap id="lessonListResultMap" type="CourseLesson">
<id property="id" column="lessonid"/>
<result property="courseId" column="course_id"/>
<result property="sectionId" column="section_id"/>
<result property="theme" column="theme"/>
<result property="duration" column="duration"/>
<result property="isFree" column="is_free"/>
<result property="orderNum" column="order_num"/>
<result property="status" column="status"/>
<result property="isDel" column="is_del"/>
</resultMap>
</mapper>
3.3.7.3、service层
public interface CourseContentService {
/*展示课程内容*/
public List<CourseSection> findSectionAndLessonByCourseId(Integer courseId);
}
import java.util.List;
@Service
@Transactional
public class CourseContentServiceImpl implements CourseContentService {
@Autowired
private CourseContentMapper courseContentMapper;
@Override
public List<CourseSection> findSectionAndLessonByCourseId(Integer courseId) {
return courseContentMapper.findSectionAndLessonByCourseId(courseId);
}
}
3.3.7.4、web层
@RestController
@RequestMapping("/courseContent")
public class CourseContentController {
@Autowired
private CourseContentService courseContentService;
/*查询课程内容*/
@RequestMapping("/findSectionAndLesson")
public ResponseResult findSectionAndLessonByCourseId(@RequestParam Integer courseId){
// 调用service
List<CourseSection> sectionList = courseContentService.findSectionAndLessonByCourseId(courseId);
// 封装返回数据
ResponseResult res = new ResponseResult(true, 200, "成功", sectionList);
return res;
}
}
3.3.7.5、postman测试
3.3.8、回显章节对应的课程信息
- 名称: findCourseById
- 描述: 回显章节对应的课程信息
- URL: http://localhost:8080/ssm-web/courseContent/findCourseByCourseId
- 请求方式: GET
- 请求参数
参数名称 | 参数说明 | in | 是否必须 | 数据类型 | schema |
---|---|---|---|---|---|
courseId | 课程id | true | int |
- 请求示例
http://localhost:8080/ssm-web/courseContent/findCourseByCourseId?courseId=15
- 响应结果示例
{
"success": true,
"state": 200,
"message": "响应成功",
"content": {
"id": 19,
"courseName": "全栈工程师",
}
}
3.3.8.1、dao层
/*回显章节对应的课程信息*/
public Course findCourseByCourseId(Integer courseId);
<select id="findCourseByCourseId" resultType="course">
select id, course_name from course where id = #{courseId}
</select>
3.3.8.2、service层
/*回显信息*/
@Override
public Course findCourseByCourseId(Integer courseId) {
return courseContentMapper.findCourseByCourseId(courseId);
}
/*回显信息*/
public Course findCourseByCourseId(Integer courseId);
3.3.8.3、web层
@RequestMapping("/findCourseByCourseId")
public ResponseResult findCourseByCourseId(@RequestParam Integer courseId){
Course course = courseContentService.findCourseByCourseId(courseId);
ResponseResult res = new ResponseResult(true, 200, "查询课程信息成功", course);
return res;
}
3.3.8.4、postman测试
3.3.9、新建章节信息
- 名称: saveOrUpdateSection
- 描述: 保存和修改章节信息
- URL: http://localhost:8080/ssm-web/courseContent/saveOrUpdateSection
- 请求方式: POST
- 请求参数
字段 | 说明 | 类型 | 是否必需 | 备注 |
---|---|---|---|---|
id | 章节ID | int | 否 | 添加操作不携带id, 修改操作必须携带ID |
course_id | 课程ID | int | 是 | |
section_name | 章节名称 | String | 是 | |
description | 章节描述 | String | 是 | |
order_num | 章节排序 | int | 是 |
- 请求参数示例
//新增
{
"courseId":8,
"sectionName":"Vue脚手架",
"description":"快速搭建Vue项目",
"orderNum":2
}
//修改
{
"id":13,
"sectionName":"Vue路由",
"description":"单页面应用导航",
"orderNum":0
}
- 响应结果示例
{
"success": true,
"state": 200,
"message": "响应成功",
"content": null
}
3.3.9.1、dao层
/*保存章节*/
public void saveSection(CourseSection section);
3.3.9.2、service层
@Override
public void saveSection(CourseSection section) {
/*补全信息*/
Date date = new Date();
section.setCreateTime(date);
section.setUpdateTime(date);
courseContentMapper.saveSection(section);
}
3.3.9.3、web层
@RequestMapping("/saveOrUpdateSection")
public ResponseResult saveOrUpdateSection(@RequestBody CourseSection section){
courseContentService.saveSection(section);
return new ResponseResult(true, 200, "新增章节成功", null);
}
3.3.9.4、postman测试
3.3.10、修改章节状态
- 名称: updateSectionStatus
- 描述: 修改章节状态
- URL: http://localhost:8080/ssm-web/courseContent/updateSectionStatus
- 请求方式: GET
- 请求参数
字段 | 说明 | 类型 | 是否必需 | 备注 |
---|---|---|---|---|
id | 章节ID | int | 是 | |
status | 章节状态 | int | 是 | 状态,0:隐藏;1:待更新;2:已发布 |
- 请求示例
http://localhost:8080/ssm-web/courseContent/updateSectionStatus?id=7&status=1
- 响应结果示例
{
"success": true,
"state": 200,
"message": "响应成功",
"content": {
"status": 1
}
}
3.3.10.1、dao层
/*修改章节状态*/
public void updateSectionStatus(Course course);
3.3.10.2、service层
@Override
public void updateSectionStatus(Integer id, Integer status) {
// 封装信息
Course course = new Course();
course.setId(id);
course.setStatus(status);
course.setUpdateTime(new Date());
// 更新状态
courseContentMapper.updateSectionStatus(course);
}
3.3.10.3、web层
@RequestMapping("/updateSectionStatus")
public ResponseResult updateSectionStatus(@RequestParam Integer id, @RequestParam Integer status){
courseContentService.updateSectionStatus(id, status);
HashMap<Object, Object> map = new HashMap<>();
ResponseResult res = new ResponseResult(true, 200, "更新章节状态成功", map);
return res;
}
3.3.10.4、postman测试
3.3.11、修改章节信息
3.3.11.1、dao层
/*修改章节信息*/
public void updateSection(CourseSection courseSection);
<update id="updateSection" parameterType="CourseSection">
UPDATE course_section
<trim prefix="SET" suffixOverrides=",">
<if test="sectionName != null and sectionName != ''">
section_name = #{sectionName},
</if>
<if test="description != null and description != ''">
description = #{description},
</if>
<if test="orderNum != null and orderNum != '' or orderNum == 0">
order_num = #{orderNum},
</if>
<if test="updateTime != null">
update_time=#{updateTime}
</if>
</trim>
<where>
<if test="id != null and id != ''">
id = #{id}
</if>
</where>
</update>
3.3.11.2、service层
// 修改章节
@Override
public void updateSection(CourseSection courseSection) {
// 补全信息
Date date = new Date();
courseSection.setUpdateTime(date);
courseContentMapper.updateSection(courseSection);
}
3.3.11.3、web层
@RequestMapping("/saveOrUpdateSection")
public ResponseResult saveOrUpdateSection(@RequestBody CourseSection section){
if(section.getId() == null) {
courseContentService.saveSection(section);
return new ResponseResult(true, 200, "新增章节成功", null);
}else{
courseContentService.updateSection(section);
return new ResponseResult(true, 200, "更新章节成功", null);
}
}
3.3.11.4、postman测试
3.3.12、新建课时信息以及修改课时信息
- 名称: saveLesson
- 描述: 保存课时信息
- URL: http://localhost:8080/ssm-web/courseContent/saveLesson
- 请求方式: POST
- 请求参数
字段 | 说明 | 类型 | 是否必需 | 备注 |
---|---|---|---|---|
id | 课时ID | int | 否 | 添加操作不携带id, 修改操作必须携带ID |
courseId | 课程ID | int | 是 | |
sectionId | 章节ID | int | 是 | |
theme | 课时名称 | String | 是 | |
duration | 课时时长(分钟) | int | 是 | |
isFree | 是否免费,0 免费,1 付费 | int | 是 | |
orderNum | 排序字段 | int | 是 |
- 请求示例
//新建
{
"courseId":7,
"sectionId":7,
"theme":"文案高手养成",
"duration":15,
"isFree":0,
"orderNu":2
}
3.3.12.1、dao层
/*保存课时信息*/
public void saveLesson(CourseLesson courseLesson);
<insert id="saveLesson" parameterType="CourseLesson">
INSERT INTO course_lesson (
id,course_id,
section_id,
theme,
duration,
is_free,
order_num,
create_time,
update_time
)VALUES(#{id},#{courseId},#{sectionId},#{theme},#{duration},#{isFree},
#{orderNum},#{createTime},#{updateTime});
</insert>
<update id="updateLesson" parameterType="CourseLesson">
update course_lesson
<trim prefix="SET" suffixOverrides=",">
<if test="theme != null and theme != ''">
theme=#{theme},
</if>
<if test="duration != null and duration != ''">
duration=#{duration},
</if>
<if test="isFree != null and isFree != ''">
is_free=#{isFree},
</if>
<if test="orderNum != null and orderNum != '' or orderNum == 0">
order_num=#{orderNum},
</if>
<if test="updateTime != null">
update_time=#{updateTime},
</if>
</trim>
<where>
<if test="id != null and id != ''">
id=#{id}
</if>
</where>
</update>
3.3.12.2、service层
@Override
public void saveLesson(CourseLesson courseLesson) {
// 补全信息
Date date = new Date();
courseLesson.setCreateTime(date);
courseLesson.setUpdateTime(date);
courseContentMapper.saveLesson(courseLesson);
}
@Override
public void updateLesson(CourseLesson courseLesson) {
// 补全信息
Date date = new Date();
courseLesson.setUpdateTime(date);
courseContentMapper.updateLesson(courseLesson);
}
3.3.12.3、web层
@RequestMapping("/saveOrUpdateLesson")
public ResponseResult saveOrUpdateLesson(@RequestBody CourseLesson courseLesson){
if(courseLesson.getId() == null){
courseContentService.saveLesson(courseLesson);
return new ResponseResult(true, 200, "保存信息成功", null);
}else{
courseContentService.updateLesson(courseLesson);
return new ResponseResult(true, 200, "修改信息成功", null);
}
}