SSM单体项目:拉勾教育后台管理系统(上)

任务一:课程模块

1.项目架构

1.1 项目介绍

拉勾教育后台管理系统,是提供给拉勾教育的相关业务人员使用的一个后台管理系统, 业务人员可以在这个后台管理系统中,对课程信息、广告信息、用户信息、 权限信息等数据进行维护.

在 web阶段,我们已经完成了拉勾教育后台管理系统中课程模块, 接下来将对拉勾教育后台管理系统进行升级改造,基于SSM框架来完成课程信息模块,广告信息模块,用户信息模块,权限信息模块

1.2 页面原型展示

访问 http://eduboss.lagou.com

用户名:18201288771 密码:111111

image-20211204140741328

1.3 技术选型

1.3.1 前端技术选型

image-20211204134323312

1.3.2 后端技术选型

image-20211204134339955

1.4 项目开发环境

  • 开发工具
    • 后端: IDEA 2019
    • 前端: VS code
    • 数据库客户端工具: SQLYog
  • 开发环境
    • JDK 11
    • Maven 3.6.3
    • MySQL 5.7

2.Maven进阶使用(Maven聚合工程)

2.1 maven基础知识回顾

2.1.1 maven介绍

maven 是一个项目管理工具,主要作用是在项目开发阶段对Java项目进行依赖管理和项目构建。

依赖管理:就是对jar包的管理。通过导入maven坐标,就相当于将仓库中的jar包导入了当前项目中。

项目构建:通过maven的一个命令就可以完成项目从清理、编译、测试、报告、打包,部署整个过程。

image-20211204134527530

2.1.2 maven的仓库类型

1.本地仓库

2.远程仓库

①maven中央仓库(地址:http://repo2.maven.org/maven2/)
②maven私服(公司局域网内的仓库,需要自己搭建)
③其他公共远程仓库(例如apache提供的远程仓库,地址:http://repo.maven.apache.org/maven2/)

本地仓库---》maven私服---》maven中央仓库

2.1.3 maven常用命令

clean: 清理

compile:编译

test: 测试

package:打包

install: 安装

2.1.4 maven坐标书写规范

image-20211204134707280

2.2 maven的依赖传递

2.2.1 什么是依赖传递

在maven中,依赖是可以传递的,假设存在三个项目,分别是项目A,项目B以及项目C。假设C依赖B,B依赖A,那么我们可以根据maven项目依赖的特征不难推出项目C也依赖A。

image-20211204145008193

image-20211204145820819

通过上面的图可以看到,我们的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.2.2 如何解决依赖冲突

1.使用maven提供的依赖调解原则
第一声明者优先原则
路径近者优先原则
2.排除依赖
3.锁定版本

2.2.3 依赖调节原则——第一声明者优先原则

在 pom 文件中定义依赖,以先声明的依赖为准。其实就是根据坐标导入的顺序来确定最终使用哪个传递过来的依赖。

image-20211204151519233

结论:通过上图可以看到,spring-aop和spring-webmvc都传递过来了spring-beans,但是因为spring-aop在前面,所以最终使用的spring-beans是由spring-aop传递过来的,而spring-webmvc传递过来的spring-beans则被忽略了。

2.2.4 依赖调节原则——路径近者优先原则

image-20211204151545116

总结:直接依赖大于依赖传递

2.2.5 排除依赖

可以使用exclusions标签将传递过来的依赖排除出去。

image-20211204151415320

2.2.6 版本锁定

采用直接锁定版本的方法确定依赖jar包的版本,版本锁定后则不考虑依赖的声明顺序或依赖的路径,以锁定的版本为准添加到工程中,此方法在企业开发中经常使用。

版本锁定的使用方式:

第一步:在dependencyManagement标签中锁定依赖的版本
第二步:在dependencies标签中声明需要导入的maven坐标

①在dependencyManagement标签中锁定依赖的版本

image-20211204151611610

②在dependencies标签中声明需要导入的maven坐标

image-20211204151631977

2.2.7 properties标签的使用

<properties>
        <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> 

2.3 maven聚合工程(分模块)

概念:

在现实生活中,汽车厂家进行汽车生产时,由于整个生产过程非常复杂和繁琐,工作量非常大,所以厂家都会将整个汽车的部件分开生产,最终再将生产好的部件进行组装,形成一台完整的汽车。

image-20211204135238164

2.3.1 分模块构建maven工程分析

在企业项目开发中,由于项目规模大,业务复杂,参与的人员比较多,一般会通过合理的模块拆分将一个大型的项目拆分为N多个小模块,分别进行开发。而且拆分出的模块可以非常容易的被其他模块复用

常见的拆分方式有两种:

第一种:按照业务模块进行拆分,每个模块拆分成一个maven工程,例如将一个项目分为用户模块,订单模块,购物车模块等,每个模块对应就是一个maven工程

第二种:按照层进行拆分,例如持久层、业务层、表现层等,每个层对应就是一个maven工程

不管上面那种拆分方式,通常都会提供一个父工程,将一些公共的代码和配置提取到父工程中进行统一管理和配置。

image-20211204152947527

2.3.2 maven工程的继承

在Java语言中,类之间是可以继承的,通过继承,子类就可以引用父类中非private的属性和方法。同样,在maven工程之间也可以继承,子工程继承父工程后,就可以使用在父工程中引入的依赖。继承的目的是为了消除重复代码。

image-20211204151734200

2.3.3 maven工程的聚合

在maven工程的pom.xml文件中可以使用标签< modules>将其他maven工程聚合到一起,聚合的目的是为了进行统一操作

例如拆分后的maven工程有多个,如果要进行打包,就需要针对每个工程分别执行打包命令,操作起来非常繁琐。这时就可以使用标签将这些工程统一聚合到maven父工程中,需要打包的时候,只需要在此工程中执行一次打包命令,其下被聚合的工程就都会被打包了。

image-20211204135414253

2.3.4 maven聚合工程_搭建拉勾教育后台管理系统

工程整体结构如下:

1)lagou_edu_home_parent为父工程,其余工程为子工程,都继承父工程lagou_edu_home_parent

2)lagou_edu_home_parent工程将其子工程都进行了聚合

3)子工程之间存在依赖关系:

​ ssm_domain依赖ssm_utils

​ ssm_dao依赖ssm_domain

​ ssm_service依赖ssm_dao

​ ssm_web依赖ssm_service

image-20211204155340178

image-20211204155358440

父工程lagou_edu_home_parent构建

修改pom.xml,添加依赖

<properties>
        <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>
    <dependencies>
        <!--mybatis坐标-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</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.12</version>
        </dependency>
        <!--spring坐标-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <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-tx</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
        </dependency>
        <!--mybatis整合spring坐标-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!--springMVC坐标-->
        <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>
② 子工程ssm_utils构建
③ 子工程ssm_domain构建
<!-- 依赖ssm_utils -->
    <dependencies>
        <dependency>
            <groupId>com.lagou</groupId>
            <artifactId>ssm_utils</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
④ 子工程ssm_dao构建

​ 配置ssm_domain工程的pom.xml文件

 <!--依赖ssm_domain-->
  <dependencies>
        <dependency>
            <groupId>com.lagou</groupId>
            <artifactId>ssm_domain</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

创建DAO接口和Mapper映射文件

package com.lagou.dao;

import com.lagou.domain.Test;

import java.util.List;

public interface TestMapper {
    public List<Test> 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.lagou.dao.TestMapper">
    <select id="findAllTest" resultType="com.lagou.domain.Test">
        select * from test;
    </select>
</mapper>

在resources目录下创建spring配置文件applicationContext-dao.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">
    <!--spring整合mybatis-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    
    <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的创建权交给了spring 生产sqlSession-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="typeAliasesPackage" value="com.lagou.domain"></property>
        <!--引入加载mybatis的核心配置文件,可以不用去加载-->
         <property name="configLocation" value="classpath:SqlMapConfig.xml"></property>
    </bean>
    <!--mapper映射扫描 MapperScannerConfigurer扫描该包下所有接口,生成代理对象存到IOC容
器中-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.lagou.dao"></property>
    </bean>
</beans>

sqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!-- 是否开启自动驼峰命名规则(camel case)映射,
			即从数据库列名 A_COLUMN 到属性名aColumn 的类似映射  a_name aName-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
</configuration>
⑤子工程ssm_service构建

​ 第一步:创建ssm_service工程

​ 第二步:配置ssm_service工程的pom.xml文件

<dependencies>
        <dependency>
            <groupId>com.lagou</groupId>
            <artifactId>ssm_dao</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

第三步:创建TestService接口和实现类

public interface TestService {
    public List<Test> findAllTest();
    
}
@Service
public class TestServiceImpl implements TestService {
    @Autowired
    private TestMapper testMapper;
    @Override
    public List<Test> findAllTest() {
        List<Test> allTest = testMapper.findAllTest();
        return allTest;
    }
}

第四步:创建spring配置文件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.lagou.service"></context:component-scan>
    <import resource="classpath:applicationContext_dao.xml"/>
</beans>
⑥子工程ssm_web构建

​ 第一步:创建maven_web工程,注意打包方式为war

​ 第二步:配置maven_web工程的pom.xml文件

<dependencies>
        <dependency>
            <groupId>com.lagou</groupId>
            <artifactId>ssm_service</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
</dependencies>

第三步:创建Controller

@RestController
@RequestMapping("/test")
public class TestController {
    @Autowired
    private TestService testService;
    @RequestMapping("/findAllTest")
    public List<Test> findAllTest(){
        List<Test> allTest = testService.findAllTest();
        return allTest;
    }
}

第四步: 创建springmvc配置文件springmvc.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">
    <!--1.组件扫描:只扫描controller-->
    <context:component-scan base-package="com.lagou.controller"></context:component-scan>
    <!--2.mvc注解增强:处理器映射器及处理器适配器-->
    <mvc:annotation-driven></mvc:annotation-driven>
    <!--3.视图解析器-->
<!--    <bean id="resourceViewResolve" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".html"></property>
    </bean>-->
    <!--4.放行静态资源-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>
</beans>

第五步:编写applicationContext.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">
    <!--引入:applicationContext_service.xml-->
    <import resource="classpath:applicationContext_service.xml"/>
</beans>

第六步:配置web.xml

<!--前端控制器-->
    <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>
    <!--中文乱码过滤器:解决post方式提交的乱码-->
    <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.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>

3.拉勾教育后台管理系统研发

3.1 课程管理模块功能分析

在本次的项目中,首先先来完成拉勾教育后台管理系统的 课程管理模块, 课程管理模块包含了多条件查询、 图片上传、 新建&修改课程、课程状态管理、课程内容展示、回显章节对应的课程信息、新建&修改章节信息、修改章节状态、 新建&修改课时信息等接口的编写

3.1.1 课程管理

  • 实现以下功能:
    • 多条件查询
    • 图片上传
    • 新建课程信息
    • 回显课程信息
    • 修改课程信息
    • 课程状态管理
    • 课程内容展示
    • 回显章节对应的课程信息
    • 新建&修改章节信息
    • 修改章节状态
    • 新建课时信息

image-20211204140818643

3.2 课程管理模块表设计

3.2.1 创建数据库及表

在资料中找到 ssm_lagou_edu.sql,使用SQLYog 执行SQL脚本 ,导入表结构及表信息

image-20211204140255333

3.2.2 表关系介绍

1.ER图

image-20211204151828681

2.数据实体描述

2.1 课程表

image-20211204140456625

image-20211204140538787

image-20211204140550907

image-20211204140603997

3.3 课程管理模块接口实现

多条件课程列表查询

需求分析

根据课程名称及课程状态进行多条件查询

image-20211204140859051

查看接口文档,进行编码

查看接口文档

实体类: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;
 // getter/setter....

ResponseResult

public class ResponseResult {
    private Boolean success;
    private Integer state;
    private String message;
    private Object content;
public ResponseResult() {
}
public ResponseResult(Boolean success, Integer state, String message, Object 
content) {
    this.success = success;
    this.state = state;
    this.message = message;
    this.content = content;
}
        //getter/setter..
}

实体类:CourseVo(View Object表现层对象:主要用于表现层来接收参数的)

public class CourseVO {
    /**
     * 课程名称
     * */
    private String courseName;
    /**
     * 课程状态
     * */
    private Integer status;
    
     // getter/setter....
}

Dao层:CourseMapper

public interface CourseMapper {
    /**
     * 多条件课程列表查询
     */
    public List<Course> findCourseByConditioin(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.lagou.dao.CourseMapper">
    <!--    多条件课程列表查询    -->
    <select id="findCourseByConditioin" 
parameterType="com.lagou.domain.CourseVO" resultType="com.lagou.domain.Course">
        SELECT
            id,
            course_name,
            price,
            sort_num,
            STATUS
        FROM
        course
        <where>
            <if test="true">
                and is_del != 1
            </if>
            <if test="courseName != null and courseName != ''">
                and course_name like concat('%',#{courseName},'%')
            </if>
            <if test="status != null and status !=''">
                and status = #{status}
            </if>
        </where>
    </select>

Service层:CourseService

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) {
        List<Course> courseList = courseMapper.findCourseByConditioin(courseVO);
        return courseList;
    }

Web层:CourseController

@RestController
@RequestMapping("/course")
public class CourseController {
    @Autowired
    private CourseService courseService;
    /**
     * 查询课程信息&条件查询 接口
     * */
    @RequestMapping("/findCourseByConditioin")
    public ResponseResult findCourseByConditioin(@RequestBody CourseVO courseVO)
{
        List<Course> courseList = courseService.findCourseByConditioin(courseVO);
        ResponseResult result = new ResponseResult(true,200,"响应成功",courseList);
        return result;
    }

Postman测试接口

课程图片上传

需求分析:
需求:在新增课程页面需要进行图片上传,并回显图片信息

image-20211204151917916

查看接口文档,进行编码

查看接口文档

springmvc.xml

<!--5.配置文件解析器-->
<!-- 此处id为固定写法,不能随便取名-->
<bean id="multipartResolver" 
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="1048576"></property>
</bean>

Web层:CourseController

/**
     * 图片上传接口
     * */
    @RequestMapping("/courseUpload")
    public ResponseResult fileUpload(@RequestParam("file")MultipartFile file, 
HttpServletRequest request){
        try {
            //1.判断文件是否为空
            if(file.isEmpty()){
                throw new RuntimeException();
            }
            //2.获取项目部署路径
            // D:\apache-tomcat-8.5.56\webapps\ssm_web\
            String realPath = request.getServletContext().getRealPath("/");
            // D:\apache-tomcat-8.5.56\webapps\
            String webappsPath = 
realPath.substring(0,realPath.indexOf("ssm_web"));
            //3.获取原文件名
            String fileName = file.getOriginalFilename();
            //4.新文件名
            String newFileName =  System.currentTimeMillis() + 
fileName.substring(fileName.lastIndexOf("."));
            //5.上传文件
            String uploadPath = webappsPath+"upload\\";
            File filePath = new File(uploadPath,newFileName);
            //如果目录不存在就创建目录
            if(!filePath.getParentFile().exists()){
                filePath.getParentFile().mkdirs();
                System.out.println("创建目录: " + filePath);
            }
            file.transferTo(filePath);
            //6.将文件名和文件路径返回
            Map<String,String> map = new HashMap<>();
            map.put("fileName",newFileName);
            map.put("filePath",LOCAL_URL+"/upload/"+newFileName);
            ResponseResult result = new ResponseResult(true,200,"响应成功",map);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

Postman测试接口

新建课程信息

需求分析:

填写好新增课程信息后,点击保存,将表单信息保存到数据库中

image-20211204151941555

查看接口文档,进行编码

查看接口文档
Dao层:CourseMapper

public interface CourseMapper {
    /**
     * 保存课程信息
     */
    public int saveCourse(Course course);
    /**
     * 保存讲师信息
     * */
    public void saveTeacher(Teacher teacher);
    
} 

CourseMapper.xml

<!--  保存课程信息  -->
<insert id="saveCourse" parameterType="com.lagou.domain.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="java.lang.Integer" order="AFTER" keyProperty="id">
        SELECT LAST_INSERT_ID();
    </selectKey>
</insert>
<!-- 保存讲师信息   -->
<insert id="saveTeacher" parameterType="com.lagou.domain.Teacher">
    INSERT INTO teacher(
        course_id,
        teacher_name,
        POSITION,
        description,
        create_time,
        update_time
    ) VALUES(#{courseId},#{teacherName},#{position},#{description},#
{createTime},#{updateTime});
</insert>

Service层:CourseService

public interface CourseService {
    /**
     * 保存课程信息
     * */
    public void saveCourseOrTeacher(CourseVO courseVO);
}
@Service
public class CourseServiceImpl implements CourseService {
    @Autowired
    private CourseMapper courseMapper;
    @Override
    public void saveCourseOrTeacher(CourseVO courseVO) {
        try {
            //封装课程信息
            Course course = new Course();
            BeanUtils.copyProperties(course,courseVO);
            //补全信息
            Date date = new Date();
            course.setCreateTime(date);
            course.setUpdateTime(date);
            //保存课程
            courseMapper.saveCourse(course);
            //获取新插入数据的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();
        }
    }
 
    }

Web层:CourseController

@RestController
@RequestMapping("/course")
public class CourseController {
    @Autowired
    private CourseService courseService;
    /**
     * 保存&修改课程信息接口
     * */
    @RequestMapping("/saveOrUpdateCourse")
    public ResponseResult saveOrUpdateCourse(@RequestBody CourseVO courseVO){
        try {
            if(courseVO.getId() == null){
                courseService.saveCourseOrTeacher(courseVO);
                ResponseResult result = new ResponseResult(true,200,"响应成
功",null);
                return result;
            }else{
                courseService.updateCourseOrTeacher(courseVO);
                ResponseResult result = new ResponseResult(true,200,"响应成
功",null);
                return result;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

Postman测试接口

回显课程信息

需求分析:

点击编辑按钮,回显课程信息

查看接口文档,进行编码

查看接口文档

Dao层:CourseMapper

public interface CourseMapper {
    /**
     * 根据id 获取课程信息
    * */
    public CourseVO findCourseById(int id);
    
} 

CourseMapper.xml

<!--  根据id查询  -->
<select id="findCourseById" parameterType="int" 
resultType="com.lagou.domain.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>

Service层:CourseService

public interface CourseService {
    /**
     * 根据id获取课程信息
     * */
    public CourseVO findCourseById(int id);
}
@Service
public class CourseServiceImpl implements CourseService {
    @Autowired
    private CourseMapper courseMapper;
    @Override
    public CourseVO findCourseById(int id) {
    return courseMapper.findCourseById(id);
        }
    }

Web层:CourseController

@RestController
@RequestMapping("/course")
public class CourseController {
    @Autowired
    private CourseService courseService;
     /**
     * 根据id获取课程信息
     * */
     @RequestMapping("/findCourseById")
    public ResponseResult findCourseById(@RequestParam int id) {
     try {
        CourseVO courseVO = courseService.findCourseById(id);
        ResponseResult result = new ResponseResult(true,200,"响应成功",courseVO);
        return result;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
        }
    }

Postman测试接口

修改课程信息

需求分析:
点击保存按钮,将修改后的课程信息保存到数据库中

image-20211204142023165

查看接口文档,进行编码
查看接口文档
Dao层:CourseMapper

public interface CourseMapper {
    /**
     * 修改课程信息
     * */
    public void updateCourse(Course course);
    /**
     * 修改讲师信息
     * */
    public void updateTeacher(Teacher teacher);
    
}  

CourseMapper.xml

<!--  修改课程信息  -->
    <update id="updateCourse" parameterType="com.lagou.domain.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="com.lagou.domain.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>

Service层:CourseService

public interface CourseService {
    /**
     * 修改课程信息
     * */
    public void updateCourseOrTeacher(CourseVO courseVO);
}
@Service
public class CourseServiceImpl implements CourseService {
    @Autowired
    private CourseMapper courseMapper;
    @Override
    public void updateCourseOrTeacher(CourseVO courseVO) {
        try {
            //封装课程信息
            Course course = new Course();
            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();
        }
    }

Web层:CourseController

@RestController
@RequestMapping("/course")
public class CourseController {
    @Autowired
    private CourseService courseService;
    /**
     * 保存&修改课程信息接口
     * */
    @RequestMapping("/saveOrUpdateCourse")
    public ResponseResult saveOrUpdateCourse(@RequestBody CourseVO courseVO){
        try {
            if(courseVO.getId() == null){
                courseService.saveCourseOrTeacher(courseVO);
                ResponseResult result = new ResponseResult(true,200,"响应成
功",null);
                return result;
            }else{
                courseService.updateCourseOrTeacher(courseVO);
                ResponseResult result = new ResponseResult(true,200,"响应成
功",null);
                return result;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
            }
    }

Postman测试接口

课程状态管理

需求分析:
在课程列表展示页面中,可以通过点击 上架/下架按钮,修改课程状态

image-20211204142251418

查看接口文档,进行编码

查看接口文档
Dao层:CourseMapper

public interface CourseMapper {
    /**
     * 修改课程状态
     * */
    public void updateCourseStatus(Course course);
}    

CourseMapper.xml

<!--  修改课程状态  -->
    <update id="updateCourseStatus" parameterType="com.lagou.domain.Course">
        UPDATE course SET STATUS = #{status} ,update_time = #{updateTime} WHERE 
id = #{id}
    </update>

Service层:CourseService

/**
     * 修改课程状态
     * */
    public void updateCourseStatus(int id,int status);
@Override
    public void updateCourseStatus(int id,int status) {
        try {
            //封装数据
            Course course = new Course();
            course.setStatus(status);
            course.setId(id);
            course.setUpdateTime(new Date());
            //调用Dao
            courseMapper.updateCourseStatus(course);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Web层:CourseController

/**
     * 修改课程状态
     * */
    @RequestMapping("/updateCourseStatus")
    public ResponseResult updateCourseStatus(@RequestParam int id,@RequestParam 
int status){
        try {
            //执行修改操作
                courseService.updateCourseStatus(id, status);
            //保存修改后的状态,并返回
            Map<String,Integer> map = new HashMap<>();
            map.put("status",status);
            ResponseResult result = new ResponseResult(true,200,"响应成功",map);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

Postman测试接口

课程内容展示

需求分析:
需求:点击内容管理,展示课程对应的课程内容(课程内容包含了章节和课时)

image-20211204142451978

查看接口文档,进行编码:
查看接口文档:
CourseSection

/**
 * 章节类
 * */
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;
    public List<CourseLesson> getLessonList() {
        return lessonList;
    }
    public void setLessonList(List<CourseLesson> lessonList) {
        this.lessonList = lessonList;
    }

Dao层:CourseContentMapper

public interface CourseContentMapper {
    /**
     * 查询课程下的章节与课时信息
     * */
    public List<CourseSection> findSectionAndLessonByCourseId(int courseId);
  
  }
<!--  根据课程ID 查询课程内容(章节与课时)  -->
<select id="findSectionAndLessonByCourseId" parameterType="int" 
resultMap="BaseResultMap">
        SELECT
        cs.*,
        <include refid="lesson_column_list"/>
        FROM course_section cs
        LEFT JOIN  course_lesson cl ON cs.id = cl.section_id
        WHERE cs.course_id = #{courseId} ORDER BY cs.order_num ;
    </select>
    <!--  一对多配置,一个章节下有多个课时  -->
    <resultMap id="BaseResultMap" type="com.lagou.domain.CourseSection">
        <result property="id" column="id"></result>
        <result property="courseId" column="course_id"></result>
        <result property="sectionName" column="section_name"></result>
        <result property="description" column="description"></result>
        <result property="orderNum" column="order_num"></result>
        <result property="status" column="status"></result>
        <!-- 使用 collection,配置一对多关系 -->
        <collection property="lessonList" resultMap="lessionListResultMap"/>
    </resultMap>
    
    <resultMap id="lessionListResultMap" type="com.lagou.domain.CourseLesson">
        <id property="id" column="lessonId"></id>
        <result property="courseId" column="course_id"></result>
        <result property="sectionId" column="section_id"></result>
        <result property="theme" column="theme"></result>
        <result property="duration" column="duration"></result>
        <result property="isFree" column="is_free"></result>
        <result property="orderNum" column="order_num"></result>
        <result property="status" column="status"></result>
    </resultMap>
    <!-- 课时表字段信息   -->
    <sql id="lesson_column_list">
        cl.id as lessonId,
        cl.course_id,
        cl.section_id,
        cl.theme,
        cl.duration,
        cl.is_free,
        cl.order_num,
        cl.status
    </sql>

Service层:CourseContentService

public interface CourseContentService {
    public List<CourseSection> findSectionAndLessonByCourseId(int courseId);
    
  }  
@Service
public class CourseContentServiceImpl implements CourseContentService {
    @Autowired
    private CourseContentMapper contentMapper;
    @Override
    public List<CourseSection> findSectionAndLessonByCourseId(int courseId) {
        List<CourseSection> sectionList = 
contentMapper.findSectionAndLessonByCourseId(courseId);
        return sectionList;
    }
   }

Web层:CourseContentController

@RestController
@RequestMapping("/courseContent")
public class CourseContentController {
    @Autowired
    private CourseContentService contentService;
    /**
     * 查询课程内容
     * */
    @RequestMapping("/findSectionAndLesson")
    public ResponseResult findSectionAndLessonByCourseId(@RequestParam int 
courseId){
        try {
            //调用service
            List<CourseSection> sectionList = 
contentService.findSectionAndLessonByCourseId(courseId);
            //封装数据并返回
            ResponseResult result = new ResponseResult(true,200,"响应成
功",sectionList);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    }

Postman测试接口

回显章节对应的课程信息

需求分析:
需求:在课程内容界面回显课程信息

image-20211204142741122

查看接口文档,进行编码
查看接口文档:
Dao层:CourseContentMapper

public interface CourseContentMapper {
    /**
     *  回显章节对应的课程信息
     * */
    public Course findCourseByCourseId(int courseId);
  
  }
<!--  回显课程信息  -->
    <select id="findCourseByCourseId" parameterType="int" 
resultType="com.lagou.domain.Course">
        SELECT id,course_name FROM course WHERE id = #{courseId}
    </select>

Service层:CourseContentService

public interface CourseContentService {
    public Course findCourseByCourseId(int courseId);
    
  }  
@Service
public class CourseContentServiceImpl implements CourseContentService {
    @Autowired
    private CourseContentMapper contentMapper;
    @Override
    public Course findCourseByCourseId(int courseId) {
        Course course = contentMapper.findCourseByCourseId(courseId);
        return course;
    }
   }

Web层:CourseContentController

@RestController
@RequestMapping("/courseContent")
public class CourseContentController {
    @Autowired
    private CourseContentService contentService;
    /**
     * 回显章节对应的课程信息
     * */
    @RequestMapping("/findCourseByCourseId")
    public ResponseResult findCourseByCourseId(@RequestParam int courseId){
        try {
            //调用service
            Course course = contentService.findCourseByCourseId(courseId);
            ResponseResult result = new ResponseResult(true,200,"响应成
功",course);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

Postman测试接口

新建章节信息

需求分析:
在课程内容展示页面中,可以通过点击添加阶段按钮,添加章节信息

image-20211204142924308

image-20211204142930846

查看接口文档,进行编码
查看接口文档
Dao层:CourseContentMapper

/**
     * 保存章节
     * */
    public void saveSection(CourseSection section);
<!-- 保存章节 -->
    <insert id="saveSection" parameterType="com.lagou.domain.CourseSection">
        INSERT INTO course_section(
            course_id,
            section_name,
            description,
            order_num,
            STATUS,
            create_time,
            update_time
        )VALUES(#{courseId},#{sectionName},#{description},#{orderNum},
        #{status},#{createTime},#{updateTime});
    </insert>

Service层:CourseContentService

public void saveSection(CourseSection section);
@Override
    public void saveSection(CourseSection section) {
        //补全信息
        Date date = new Date();
        section.setCreateTime(date);
        section.setUpdateTime(date);
        contentMapper.saveSection(section);
    }

Web层:CourseContentController

@RequestMapping("/saveOrUpdateSection")
    public ResponseResult saveOrUpdateSection(@RequestBody CourseSection 
section) {
        try {
           
                contentService.saveSection(section);
                return new ResponseResult(true,200,"响应成功",null);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

Postman测试接口

修改章节信息

需求分析:
点击确定按钮,将修改后的章节信息保存到数据库中

image-20211204143144710

image-20211204143150844

查看接口文档,进行编码
查看接口文档
Dao层:CourseContentMapper

/**
     * 修改章节
     * */
    public void updateSection(CourseSection section);
<!-- 修改章节 -->
    <update id="updateSection" parameterType="com.lagou.domain.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>    

Service层:CourseContentService

public void updateSection(CourseSection section);
@Override
    public void updateSection(CourseSection section) {
        //补全信息
        Date date = new Date();
        section.setUpdateTime(date);
        contentMapper.updateSection(section);
    }

Web层:CourseContentController

/**
     * 保存&修改章节信息
     */
    @RequestMapping("/saveOrUpdateSection")
    public ResponseResult saveOrUpdateSection(@RequestBody CourseSection 
section) {
        try {
            //判断携带id是修改操作否则是插入操作
            if(section.getId() == null){
                contentService.saveSection(section);
                return new ResponseResult(true,200,"响应成功",null);
            }else{
                contentService.updateSection(section);
                return new ResponseResult(true,200,"响应成功",null);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

Postman测试接口

修改章节状态

需求分析:
需求:点击修改章节状态按钮,将当前章节信息的状态进行修改

image-20211204143344535

查看接口文档,进行编码
查看接口文档
Dao层:CourseContentMapper

/**
     * 修改章节状态
     * */
    public void updateSectionStatus(CourseSection section);

CourseContentMapper.xml

<!--  修改章节状态  -->
    <update id="updateSectionStatus" 
parameterType="com.lagou.domain.CourseSection">
        UPDATE course_section set
            status = #{status},
            update_time = #{updateTime}
        WHERE id = #{id}
    </update>

Service层:CourseContentService

public void updateSectionStatus(int id,int status);
@Override
    public void updateSectionStatus(int id,int status) {
        //封装数据
        CourseSection section = new CourseSection();
        section.setId(id);
        section.setStatus(status);
        section.setUpdateTime(new Date());
        contentMapper.updateSectionStatus(section);
    }

Web层:CourseContentController

/**
     * 修改章节状态
     * 状态,0:隐藏;1:待更新;2:已发布
     * */
    @RequestMapping("/updateSectionStatus")
    public ResponseResult updateSectionStatus(@RequestParam int id,@RequestParam 
int status){
        try {
            contentService.updateSectionStatus(id,status);
            //封装最新的状态信息
            Map<String,Integer> map = new HashMap<>();
            map.put("status",status);
            ResponseResult result = new ResponseResult(true,200,"响应成功",map);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

Postman测试接口

新建课时信息(自行完成)

需求分析:
需求:点击添加阶段按钮,将弹出页面填写的章节信息保存到数据库中

image-20211204143517129

查看接口文档,进行编码
查看接口文档
Dao层:CourseContentMapper

/**
     * 保存课时
     * */
    public void saveLesson(CourseLesson lesson);
<!-- 添加课时   -->
    <insert id="saveLesson" parameterType="com.lagou.domain.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>

Service层:CourseContentService

public void saveLesson(CourseLesson lesson);
@Override
    public void saveLesson(CourseLesson lesson) {
        //补全信息
        Date date = new Date();
        lesson.setCreateTime(date);
        lesson.setUpdateTime(date);
        contentMapper.saveLesson(lesson);
    }

Web层:CourseContentController

/**
     * 保存&修改课时
     * */
    @RequestMapping("/saveOrUpdateLesson")
    public ResponseResult saveOrUpdateLesson(@RequestBody CourseLesson lesson){
        try {
            if(lesson.getId() == null){
                contentService.saveLesson(lesson);
                return new ResponseResult(true,200,"响应成功",null);
            }else{
                contentService.updateLesson(lesson);
                return new ResponseResult(true,200,"响应成功",null);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

Postman测试接口

任务二:广告模块

一 广告模块功能分析

在任务二中,首先先来完成拉勾教育后台管理系统的 广告管理模块, 广告模块包含了广告位列表查询、添加&修改广告位、回显广告位名称、广告分页查询、图片上传接口、新建&修改广告、回显广告信息、广告状态上下线等接口的编写

1.1 课程管理

  • 实现以下功能:
    • 广告位列表查询
    • 添加&修改广告位
    • 回显广告位名称
    • 广告分页查询
    • 图片上传接口
    • 新建&修改广告接口
    • 回显广告信息
    • 广告状态上下线

image-20211206202037129

二 广告管理模块表设计

2.1 创建数据库及表

在资料中找到 ssm_lagou_edu.sql,使用SQLYog 执行SQL脚本 ,导入表结构及表信息

image-20211206202103493

2.2 表关系介绍

1.ER图

image-20211206202127276

2.数据实体描述

2.1 广告位表

image-20211206202143007

2.2 广告表

image-20211206202159577

三 广告管理模块接口实现

1.广告位列表查询

1.1 需求分析

需求:点击广告列表按钮进行广告列表展示

image-20211206202228158

1.2 查看接口文档,进行编码

查看接口文档

实体类:PromotionSpace

public class PromotionSpace {
    private Integer id;
    private String name;
    private String spaceKey;
    private Date createTime;
    private Date updateTime;
    private Integer isDel;
    
     @Override
    public String toString() {
        return "PromotionSpace{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", spaceKey='" + spaceKey + '\'' +
                ", createTime=" + createTime +
                ", updateTime=" + updateTime +
                ", isDel=" + isDel +
                '}';
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSpaceKey() {
        return spaceKey;
    }
    public void setSpaceKey(String spaceKey) {
        this.spaceKey = spaceKey;
    }
    public Date getCreateTime() {
        return createTime;
    }
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
    public Date getUpdateTime() {
        return updateTime;
    }
    public void setUpdateTime(Date updateTime) {
        this.updateTime = updateTime;
    }
    public Integer getIsDel() {
        return isDel;
    }
    public void setIsDel(Integer isDel) {
        this.isDel = isDel;
    }

Dao层:PromotionSpaceMapper

public interface PromotionSpaceMapper {
     /*
         获取所有的广告位
     */
    public List<PromotionSpace> findAllPromotionSpace();
}
<?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.lagou.dao.PromotionSpaceMapper">
    <select id="findAllPromotionSpace" 
resultType="com.lagou.domain.PromotionSpace">
        select * from promotion_space
    </select>
</mapper>

Service层:PromotionSpaceService

public interface PromotionSpaceService {
    /*
         获取所有的广告位
     */
    public List<PromotionSpace> findAllPromotionSpace();
}
@Service
public class PromotionSpaceServiceImpl implements PromotionSpaceService {
    @Autowired
    private PromotionSpaceMapper promotionSpaceMapper;
    @Override
    public List<PromotionSpace> findAllPromotionSpace() {
        List<PromotionSpace> allPromotionSpace = 
promotionSpaceMapper.findAllPromotionSpace();
        return allPromotionSpace;
    }
 }

Web层:PromotionSpaceController

@RestController
@RequestMapping("/PromotionSpace")
public class PromotionSpaceController {
    @Autowired
    private PromotionSpaceService promotionSpaceService;
    /*
        查询所有广告位列表
     */
    @RequestMapping("/findAllPromotionSpace")
    public ResponseResult findAllPromotionSpace(){
        List<PromotionSpace> allPromotionSpace = 
promotionSpaceService.findAllPromotionSpace();
        ResponseResult responseResult = new ResponseResult(true,200,"响应成
功",allPromotionSpace);
        return responseResult;
    }
}

Postman测试接口

2.添加&修改广告位

1.1 需求分析

添加:点击广告列表按钮进行广告列表展示

image-20211206202501405

修改:页面回显基础上,点击提交按钮 真正进行数据修改

image-20211206202517289

2.2 查看接口文档,进行编码

查看接口文档

Dao层:PromotionSpaceMapper

public interface PromotionSpaceMapper {
    /*
        添加广告位
     */
    public void savePromotionSpace(PromotionSpace promotionSpace);
    /**
     * 修改广告位
     * */
     public void updatePromotionSpace(PromotionSpace promotionSpace);
    
}
<?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.lagou.dao.PromotionSpaceMapper">
      <insert id="savePromotionSpace" 
parameterType="com.lagou.domain.PromotionSpace">
        insert into promotion_space values(null,#{name},#{spaceKey},#
{createTime},#{updateTime},#{isDel})
    </insert>
    <update id="updatePromotionSpace" 
parameterType="com.lagou.domain.PromotionSpace">
        UPDATE promotion_space SET NAME = #{name},updateTime = #{updateTime} 
where id = #{id}
    </update>
</mapper>

Service层:PromotionSpaceService

public interface PromotionSpaceService {
    void savePromotionSpace(PromotionSpace promotionSpace);
    void updatePromotionSpace(PromotionSpace promotionSpace);
}
@Service
public class PromotionSpaceServiceImpl implements PromotionSpaceService {
    @Autowired
    private PromotionSpaceMapper promotionSpaceMapper;
     @Override
    public void savePromotionSpace(PromotionSpace promotionSpace) {
        // 封装PromotionSpace
        UUID uuid = UUID.randomUUID();
        promotionSpace.setSpaceKey(uuid.toString());
        promotionSpace.setCreateTime(new Date());
        promotionSpace.setUpdateTime(new Date());
        promotionSpace.setIsDel(0);
        promotionSpaceMapper.savePromotionSpace(promotionSpace);
    }
    
    @Override
    public void updatePromotionSpace(PromotionSpace promotionSpace) {
        promotionSpace.setUpdateTime(new Date());
        promotionSpaceMapper.updatePromotionSpace(promotionSpace);
    }
 }

Web层:PromotionSpaceController

@RestController
@RequestMapping("/PromotionSpace")
public class PromotionSpaceController {
    @Autowired
    private PromotionSpaceService promotionSpaceService;
        /*
       添加&修改广告位
     */
    @RequestMapping("/saveOrUpdatePromotionSpace")
    public ResponseResult savePromotionSpace(@RequestBody PromotionSpace 
promotionSpace){
        try {
            if(promotionSpace.getId() == null){
                //新增
                promotionSpaceService.savePromotionSpace(promotionSpace);
                ResponseResult responseResult = new ResponseResult(true,200,"响应
成功","");
                return responseResult;
            }else{
                //修改
                promotionSpaceService.updatePromotionSpace(promotionSpace);
                ResponseResult responseResult = new ResponseResult(true,200,"响应
成功","");
                return responseResult;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

Postman测试接口

3.回显广告位名称

3.1 需求分析

需求:点击编辑按钮,进行广告位信息回显

image-20211206202729533

3.2 查看接口文档,进行编码

查看接口文档

Dao层:PromotionSpaceMapper

public interface PromotionSpaceMapper {
   /**
     * 根据id 查询广告位信息
     * */
    PromotionSpace findPromotionSpaceById(int id);
}
<?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.lagou.dao.PromotionSpaceMapper">
       <select id="findPromotionSpaceById" parameterType="int" 
resultType="com.lagou.domain.PromotionSpace">
         SELECT id,NAME FROM promotion_space WHERE id = #{id};
     </select>
</mapper>

Service层:PromotionSpaceService

public interface PromotionSpaceService {
        PromotionSpace findPromotionSpaceById(int id);
}
@Service
public class PromotionSpaceServiceImpl implements PromotionSpaceService {
    @Autowired
    private PromotionSpaceMapper promotionSpaceMapper;
    @Override
    public PromotionSpace findPromotionSpaceById(int id) {
        PromotionSpace promotionSpace = 
promotionSpaceMapper.findPromotionSpaceById(id);
        return promotionSpace;
    }
 }

Web层:PromotionSpaceController

@RestController
@RequestMapping("/PromotionSpace")
public class PromotionSpaceController {
    @Autowired
    private PromotionSpaceService promotionSpaceService;
      /**
     * 根据id查询 广告位信息
     * */
    @RequestMapping("/findPromotionSpaceById")
    public ResponseResult findPromotionSpaceById(@RequestParam int id){
        PromotionSpace promotionSpace = 
promotionSpaceService.findPromotionSpaceById(id);
        ResponseResult result = new ResponseResult(true,200,"响应成
功",promotionSpace);
        return result;
    }
}

4.广告分页查询

4.1 需求分析

需求:点击广告列表,对广告信息进行分页列表展示

image-20211206202939906

4.2 查看接口文档,进行编码

查看接口文档
实体类:PromotionAd

public class PromotionAd {
    // 标识
    private Integer id;
    // 广告名
    private String name;
    // 广告位id
    private Integer spaceId;
    // 精确搜索关键词
    private String keyword;
    // 静态广告的内容
    private String htmlContent;
    // 文字一
    private String text;
    // 链接一
    private String link;
    // 开始时间
    private Date startTime;
    // 结束时间
    private Date endTime;
    private Integer status;
    private Date createTime;
    private Date updateTime;
    // 优先级
    private Integer priority;
    private String img;
    
    getter/setter..
}

PromotionAdVo

public class PromotionAdVo {
    private Integer currentPage = 1;
    private Integer pageSize = 10;
    public Integer getCurrentPage() {
        return currentPage;
    }
    public void setCurrentPage(Integer currentPage) {
        this.currentPage = currentPage;
    }
    public Integer getPageSize() {
        return pageSize;
    }
    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }
}

Dao层:PromotionAdMapper

public interface PromotionAdMapper {
     /*
         分页获取所有的广告列表
     */
    public List<PromotionAd> findAllAdByPage();
}
<mapper namespace="com.lagou.dao.PromotionAdMapper">
    <resultMap id="ad_space" type="com.lagou.domain.PromotionAd">
        <id property="id" column="id"></id>
        <result property="name" column="name"/>
        <result property="spaceId" column="spaceId"/>
        <result property="keyword" column="keyword"/>
        <result property="htmlContent" column="htmlContent"/>
        <result property="text" column="text"/>
        <result property="link" column="link"/>
        <result property="startTime" column="startTime"/>
        <result property="endTime" column="endTime"/>
        <result property="createTime" column="createTime"/>
        <result property="updateTime" column="updateTime"/>
        <result property="status" column="status"/>
        <result property="priority" column="priority"/>
        <result property="img" column="img"/>
        <association property="promotionSpace" 
select="com.lagou.dao.PromotionSpaceMapper.findPromotionSpaceById" 
column="spaceId" javaType="com.lagou.domain.PromotionSpace"></association>
    </resultMap>
    <!--分页查询广告信息-->
    <select id="findAllPromotionAdByPage" resultMap="ad_space">
        select * from promotion_ad
    </select>
</mapper>

Service层:PromotionAdService
applicationContext.xml

<!--2.sqlSessionFactory-->
    <bean id="sqlSessionFactory" 
class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="typeAliasesPackage" value="com.lagou.domain"/>
        <property name="plugins">
            <array>
                <bean class="com.github.pagehelper.PageHelper">
                    <property name="properties">
                        <value>helperDialect=mysql</value>
                    </property>
                </bean>
            </array>
        </property>
        <!--引入加载mybatis核心配置文件-->
        <property name="configLocation" value="classpath:sqlMapConfig.xml">
</property>
     </bean>
public interface PromotionAdService {
    /*
         分页获取所有的广告列表
    */
    public PageInfo findAllAdByPage(PromotionAdVo adVo);
}
@Service
public class PromotionAdServiceImpl implements PromotionAdService {
    @Autowired
    private PromotionAdMapper adMapper;
    @Override
    public PageInfo findAllAdByPage(PromotionAdVo adVo) {
        PageHelper.startPage(adVo.getCurrentPage(),adVo.getPageSize());
        List<PromotionAd> allAd = adMapper.findAllAdByPage();
        PageInfo<PromotionAd> adPageInfo = new PageInfo<>(allAd);
        return adPageInfo;
    }
 }

Web层:PromotionAdController

@RestController
@RequestMapping("/PromotionAd")
public class PromotionAdController {
    @Autowired
    private PromotionAdService adService;
    /*
        分页查询所有广告信息
     */
    @RequestMapping("/findAllPromotionAd")
    public ResponseResult findAllAdByPage(PromotionAdVo adVo) {
        PageInfo allAdByPage = adService.findAllAdByPage(adVo);
        ResponseResult responseResult = new ResponseResult(true, 200, "响应成功", 
allAdByPage);
        return responseResult;
    }
}

Postman测试接口

5.图片上传接口

5.1 需求分析

需求:添加广告页面,点击上传按钮,需完成图片上传

image-20211206203243040

5.2 查看接口文档,进行编码

查看接口文档
Web层:PromotionAdController

@RestController
@RequestMapping("/PromotionSpace")
public class PromotionSpaceController {
    @Autowired
    private PromotionSpaceService promotionSpaceService;
    /*
        文件上传
     */
    @RequestMapping("/PromotionAdUpload")
    public ResponseResult fileupload(@RequestParam("file") MultipartFile file, 
HttpServletRequest request) throws IOException {
        try {
            //1.判断文件是否为空
            if (file.isEmpty()) {
                throw new RuntimeException();
            }
            //2.获取项目部署路径
            String realPath = request.getServletContext().getRealPath("/");
            String webappsPath = realPath.substring(0, 
realPath.indexOf("ssm_web"));
            //3.获取原文件名
            String fileName = file.getOriginalFilename();
            //4.新文件名
            String newFileName = System.currentTimeMillis() + 
fileName.substring(fileName.lastIndexOf("."));
            //5.上传文件
            String uploadPath = webappsPath + "upload\\";
            File filePath = new File(uploadPath, newFileName);
            //如果目录不存在就创建目录
            if (!filePath.getParentFile().exists()) {
                filePath.getParentFile().mkdirs();
                System.out.println("创建目录: " + filePath);
            }
            file.transferTo(filePath);
            //6.将文件名和文件路径返回
            Map<String, String> map = new HashMap<>();
            map.put("fileName", newFileName);
            map.put("filePath", LOCAL_URL + "/upload/" + newFileName);
            ResponseResult result = new ResponseResult(true, 200, "响应成功", 
map);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

Postman测试接口

6.新建&修改广告(自行完成)

6.1 需求分析

新建需求:点击提交按钮,将页面内容保存到数据库

image-20211206203406731

修改需求:点击编辑按钮,由前端实现数据回显,在回显页面进行数据修改,将修改后值更新到数据库中

image-20211206203420582

image-20211206203438066

6.2 查看接口文档,进行编码

查看接口文档

Dao层:PromotionAdMapper

public interface PromotionAdMapper {
       void savePromotionAd(PromotionAd promotionAd);
       void updatePromotionAd(PromotionAd promotionAd);
}
<?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.lagou.dao.PromotionAdMapper">
    <!--添加广告-->
    <insert id="savePromotionAd" parameterType="com.lagou.domain.PromotionAd" >
       INSERT  INTO promotion_ad VALUES(NULL,#{name},#{spaceId},#{keyword},#{htmlContent},#{text},#{link},
        #{startTime},#{endTime},#{createTime},#{updateTime},#{status},#{priority},#{img});
    </insert>
    <!--更新广告-->
    <update id="updatePromotionAd" parameterType="com.lagou.domain.PromotionAd" 
>
       update promotion_ad
        <trim prefix="SET" suffixOverrides=",">
            <if test="name != null and name != ''">
                name = #{name},
            </if>
            <if test="spaceId != null and spaceId != ''">
                spaceId = #{spaceId},
            </if>
            <if test="link != null">
                link=#{link},
            </if>
            <if test="status != null and status != '' or status == 0">
                status=#{status},
            </if>
            <if test="img != null">
                img=#{img},
            </if>
            <if test="text != null">
                text=#{text},
            </if>
            <if test="startTime != null">
                startTime=#{startTime},
            </if>
            <if test="endTime != null">
                endTime=#{endTime},
            </if>
            <if test="updateTime != null">
                updateTime=#{updateTime},
            </if>
        </trim>
        <where>
            <if test="id != null and id != '' ">id = #{id}</if>
        </where>
    </update>
</mapper>

Service层:PromotionAdService

public interface PromotionAdService {
       void savePromotionAd(PromotionAd promotionAd);
       void updatePromotionAd(PromotionAd promotionAd);
}
@Service
public class PromotionAdServiceImpl implements PromotionAdService {
    @Autowired
    private PromotionAdMapper adMapper;
    @Override
    public void savePromotionAd(PromotionAd promotionAd) {
        adMapper.savePromotionAd(promotionAd);
    }
    @Override
    public void updatePromotionAd(PromotionAd promotionAd) {
        adMapper.updatePromotionAd(promotionAd);
    }
 }

Web层:PromotionAdController

@RestController
@RequestMapping("/PromotionAd")
public class PromotionAdController {
    @Autowired
    private PromotionAdService adService;
    /*
        新增或更新广告位置
     */
    @RequestMapping("/saveOrUpdatePromotionAd")
    public ResponseResult saveOrUpdatePromotionAd(@RequestBody PromotionAd 
promotionAd) {
        try {
            if (promotionAd.getId() == null) {
                Date date = new Date();
                promotionAd.setCreateTime(date);
                promotionAd.setUpdateTime(date);
                adService.savePromotionAd(promotionAd);
                ResponseResult result = new ResponseResult(true, 200, "响应成功", 
null);
                return result;
            } else {
                Date date = new Date();
                promotionAd.setUpdateTime(date);
                adService.updatePromotionAd(promotionAd);
                ResponseResult result = new ResponseResult(true, 200, "响应成功", 
null);
                return result;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

Postman测试接口

7.回显广告信息(自行完成)

7.1 需求分析

需求:点击编辑按钮,进行广告位名称回显

image-20211206203640869

7.2 查看接口文档,进行编码

查看接口文档

Dao层:PromotionAdMapper

public interface PromotionAdMapper {
    /**
     * 根据id查询广告信息
     * */
    PromotionAd findPromotionAdById(int id);
}
<?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.lagou.dao.PromotionAdMapper">
      <!--  根据id查询广告信息  -->
    <select id="findPromotionAdById" parameterType="int" 
resultType="com.lagou.domain.PromotionAd">
        SELECT
            id,
            NAME,
            spaceId,
            startTime,
            endTime,
            STATUS,
            img,
            link,
            TEXT
        FROM promotion_ad WHERE id = #{id}
    </select>
</mapper>

Service层:PromotionAdService

public interface PromotionAdService {
    /*
         回显广告信息
     */
     PromotionAd findPromotionAdById(int id);
}
@Service
public class PromotionSpaceServiceImpl implements PromotionSpaceService {
    @Autowired
    private PromotionAdMapper adMapper;
    @Override
    public PromotionAd findPromotionAdById(int id) {
        PromotionAd promotionAd = adMapper.findPromotionAdById(id);
        return promotionAd;
    }
 }

Web层:PromotionAdController

@RestController
@RequestMapping("/PromotionAd")
public class PromotionAdController {
    @Autowired
    private PromotionAdService adService;
    /**
     * 根据id回显 广告数据
     * */
    @RequestMapping("/findPromotionAdById")
    public ResponseResult findPromotionAdById(@RequestParam int id){
        try {
            PromotionAd promotionAd = adService.findPromotionAdById(id);
            ResponseResult result = new ResponseResult(true,200,"响应成
功",promotionAd);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

Postman测试接口

8.广告状态上下线

8.1 需求分析

需求:点击按钮,实现状态的动态上下线

image-20211206203831801

8.2 查看接口文档,进行编码

查看接口文档
Dao层:PromotionSpaceMapper

public interface PromotionAdMapper {
     void updatePromotionAdStatus(PromotionAd promotionAd);
}
<?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.lagou.dao.PromotionAdMapper">
       <!--void updatePromotionAdStatus(PromotionAd promotionAd);-->
    <update id="updatePromotionAdStatus" parameterType="com.soldier.domian.PromotionAd">
        UPDATE promotion_ad SET STATUS = #{status} ,updatetime = #{updateTime} WHERE id = #{id}
    </update>
</mapper>

Service层:PromotionAdService

public interface PromotionSpaceService {
      void updatePromotionAdStatus(int id, int status);
}
@Service
public class PromotionSpaceServiceImpl implements PromotionSpaceService {
   @Autowired
    private PromotionAdMapper adMapper;
      @Override
    public void updatePromotionAdStatus(int id, int status) {
        PromotionAd promotionAd = new PromotionAd();
        promotionAd.setId(id);
        promotionAd.setStatus(status);
        promotionAd.setUpdateTime(new Date());
        adMapper.updatePromotionAdStatus(promotionAd);
    }
 }

Web层:PromotionAdController

@RestController
@RequestMapping("/PromotionAd")
public class PromotionAdController {
    @Autowired
    private PromotionAdService adService;
        /*
         广告位置上下线
     */
    @RequestMapping("/updatePromotionAdStatus")
    public ResponseResult updateCourseStatus(@RequestParam int id, @RequestParam 
int status) {
        try {
            //执行修改操作
            if (status == 1) {
                adService.updatePromotionAdStatus(id, status);
            } else {
                adService.updatePromotionAdStatus(id, 0);
            }
            //保存修改后的状态,并返回
            Map<String, Integer> map = new HashMap<>();
            map.put("status", status);
            ResponseResult result = new ResponseResult(true, 200, "响应成功", 
map);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

Postman测试接口

任务三:用户模块

一 用户模块功能分析

在任务二中,再来完成拉勾教育后台管理系统的用户管理模块, 广告管理模块包含了用户分页&条件查询、用户状态设置,(登陆、权限控制)等接口的编写

1.1 用户模块

  • 实现以下功能:
    • 登陆(权限模块)
    • 权限控制(权限模块)
    • 用户分页&条件查询
    • 用户状态设置
    • 分配角色(权限模块)

image-20211206204146676

image-20211206204154471

二 用户管理模块表设计

2.1 创建数据库及表

在资料中找到 ssm_lagou_edu.sql,使用SQLYog 执行SQL脚本 ,导入表结构及表信息

image-20211206204222100

2.2 表关系介绍

1.ER图

image-20211206204240136

三 用户管理模块接口实现

1.用户分页&条件查询

1.1 需求分析

需求:实现多条件分页组合查询

image-20211206204308159

2.2 查看接口文档,进行编码

查看接口文档
UserVo

public class UserVo {
    private Integer currentPage;
    private Integer pageSize;
    private String username;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date startCreateTime;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date endCreateTime;
    public Integer getCurrentPage() {
        return currentPage;
    }
    public void setCurrentPage(Integer currentPage) {
        this.currentPage = currentPage;
    }
    public Integer getPageSize() {
        return pageSize;
    }
    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
         }
    public Date getStartCreateTime() {
        return startCreateTime;
    }
    public void setStartCreateTime(Date startCreateTime) {
        this.startCreateTime = startCreateTime;
    }
    public Date getEndCreateTime() {
        return endCreateTime;
    }
    public void setEndCreateTime(Date endCreateTime) {
        this.endCreateTime = endCreateTime;
    }
}

Dao层:UserMapper

public interface UserMapper {
    /*
        查询所有用户
    */
    public List<User> findAllUserByPage(UserVo userVo);
}
<?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.lagou.dao.UserMapper">
    <!--查询所有用户-->
    <select id="findAllUserByPage" resultType="com.lagou.domain.User">
        SELECT
            id,
            NAME,
            portrait,
            phone,
            PASSWORD,
            STATUS,
            create_time
        FROM USER
        <where>
            <if test="true">
               and is_del != 1
            </if>
            <if test="username != null">
               and name = #{username}
            </if>
            <if test="startCreateTime != null and endCreateTime != null">
                and create_time BETWEEN #{startCreateTime} AND #{endCreateTime}
              </if>
        </where>
    </select>
</mapper>  

Service层:UserService

public interface UserService {
    /*
        查询所有用户
    */
    public PageInfo findAllUserByPage(UserVo userVo);
}
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Override
    public PageInfo findAllUserByPage(UserVo userVo) {
        // 使用pageHelper
        PageHelper.startPage(userVo.getCurrentPage(),userVo.getPageSize());
        List<User> allUser = userMapper.findAllUser(userVo);
        PageInfo<User> pageInfo = new PageInfo<User>(allUser);
        System.out.println("总条数:"+pageInfo.getTotal());
        System.out.println("总页数:"+pageInfo.getPages());
        System.out.println("当前页:"+pageInfo.getPageNum());
        System.out.println("每页显示长度:"+pageInfo.getPageSize());
        System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
        System.out.println("是否最后一页:"+pageInfo.isIsLastPage());
        return pageInfo;
    }
 }

Web层:UserController

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("/findAllUserByPage")
    public ResponseResult findAllUserByPage(@RequestBody UserVo userVo){
        PageInfo pageInfo = userService.findAllUserByPage(userVo);
        ResponseResult responseResult = new ResponseResult(true,200,"响应成功",pageInfo);
        List<User> list = pageInfo.getList();
        System.out.println(list);
        return responseResult;
    }
}

Postman测试接口

2.用户状态设置(自行完成)

2.1 需求分析

点击禁用,实现用户的状态变更

image-20211206204555915

用户状态:ENABLE能登录,DISABLE不能登录

2.2 查看接口文档,进行编码

查看接口文档

Dao层:UserMapper

public interface UserMapper {
    /**
     * 修改用户状态
     * */
    public void updateUserStatus(@Param("id") int id,@Param("status") String 
status);
}
<?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.lagou.dao.UserMapper">
    <!--  修改用户状态  -->
    <update id="updateUserStatus">
        UPDATE USER SET STATUS = #{status} where id = #{id};
    </update>
</mapper>

Service层:UserService

public interface UserService {
    /*
    * 修改用户状态
    * */
    public void updateUserStatus(int id, String status);
}
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
  @Override
    public void updateUserStatus(int id, String status) {
        userMapper.updateUserStatus(id,status);
    }
 }

Web层:UserController

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
     /**
     * 修改用户状态
     *     ENABLE能登录,DISABLE不能登录
     * */
    @RequestMapping("/updateUserStatus")
    public ResponseResult updateUserStatus(@RequestParam int id ,@RequestParam 
String status){
        if("ENABLE".equalsIgnoreCase(status)){
            status = "DISABLE";
        }else{
            status = "ENABLE";
        }
        userService.updateUserStatus(id,status);
        ResponseResult responseResult = new ResponseResult(true,200,"响应成
功",status);
        return responseResult;
    }
}

Postman测试接口

任务四:权限模块

一 权限概念介绍

权限权利(能做的)和限制(不能做的),在权限范围内做好自己的事情,不该看的不看,不该做的不做

认证: 验证用户名密码是否正确的过程
​ 授权: 对用户所能访问的资源进行控制(动态显示菜单、url级别的权限控制)

为什么要实现权限系统

首先系统需要进行登陆才能访问

其次不同登陆用户要有不同的权利,而且要有不同的菜单(例如财务经理针对系统中财务相关模块进行操作,人事经理针对系统中人事模块进行操作)

权限控制基本原理

1.ACL(Access Control Lists,缩写ACL)

ACL是最早也是最基本的一种访问控制机制,它的原理非常简单:每一项资源,都配有一个列表,这个列表记录的就是哪些用户可以对这项资源执行CRUD中的那些操作。当系统试图访问这项资源时,会首先检查这个列表中是否有关于当前用户的访问权限,从而确定当前用户可否执行相应的操作。总得来说,ACL是一种面向资源的访问控制模型,它的机制是围绕“资源”展开的。

2.基于角色的访问控制RBAC(Role-Based Access Control)

RBAC是把用户按角色进行归类,通过用户的角色来确定用户能否针对某项资源进行某项操作。

RBAC相对于ACL最大的优势就是它简化了用户与权限的管理,通过对用户进行分类,使得角色与权限关联起来,而用户与权限变成了间接关联。RBAC模型使得访问控制,特别是对用户的授权管理变得非常简单和易于维护,因此有广泛的应用

image-20211206205109315

规则一:每个登陆的用户,可以有多个角色;
规则二:每个角色又可以拥有多个权限(包含菜单和资源);

二 权限模块功能分析

权限模块主要细分为角色模块、菜单模块、资源模块,将针对细分的三个模块进行具体功能实现,同时会完成用户登陆、用户关联角色及动态菜单显示

2.1 权限模块管理

  • 实现以下功能:
    • 角色列表&条件查询(角色模块)
    • 分配菜单(角色模块)
    • 删除角色(角色模块)
    • 菜单列表查询(菜单模块)
    • 查询菜单信息回显(菜单模块)
    • 资源分页&多条件查询(资源模块)
    • 用户登陆(用户模块)
    • 动态菜单展示(权限模块)
    • 用户关联角色(用户模块)

image-20211206205158893

image-20211206205207671

三 权限管理模块表设计

3.1 创建数据库及表

在资料中找到 ssm_lagou_edu.sql,使用SQLYog 执行SQL脚本 ,导入表结构及表信息

image-20211206205252478

3.2 表关系介绍

1.ER图

image-20211206205316881

image-20211206205322681

image-20211206205329672

image-20211206205335611

2.数据实体描述

2.1 菜单表(menu)

image-20211206205406988

2.2 资源类表(resource_category)

2.3 资源表(resource)

image-20211206205509106

2.4 角色表(roles)

image-20211206205522912

2.5 用户-角色关系表(user_role_relation)

image-20211206205534446

2.6 角色-菜单关系表(role_menu_relation)

image-20211206205554186

2.7 角色-资源关系表(role_resource_relation)

image-20211206205609272

四 权限管理(角色模块)接口实现

1.角色列表查询&条件查询

1.1 需求分析

需求:点击角色列表按钮进行角色列表展示

image-20211206205644723

1.2 查看接口文档,进行编码

查看接口文档
实体类:Role

public class Role {
    private Integer id;
    private String code;
    private String name;
    private String description;
    private Date createdTime;
    private Date updatedTime;
    private String createdBy;
    private String updatedBy;
    
    //getter/setter...
    
}

Dao层:RoleMapper

public interface RoleMapper {
    /*
        查询角色列表(条件)
     */
    public List<Role> findAllRole(Role role);
}
<?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.lagou.dao.RoleMapper">
    <!--查询所有角色(条件)-->
    <select id="findAllRole" resultType="com.lagou.domain.Role">
        SELECT
            id,
            CODE,
            NAME,
            description,
            created_time,
            updated_time,
            created_by,
            updated_by
        FROM roles
        <where>
            <if test="name != null and name != ''">
               and name = #{name}
            </if>
        </where>
    </select>
</mapper>

Service层:RoleService

public interface RoleService {
    public List<Role> findAllRole(Role role);
}
@Service
public class RoleServiceImpl implements RoleService {
    @Autowired
    private RoleMapper roleMapper;
    @Override
    public List<Role> findAllRole(Role role) {
        List<Role> allRole = roleMapper.findAllRole(role);
        return allRole;
    }
 }

Web层:RoleController

@RestController
@RequestMapping("/role")
public class RoleController {
    @Autowired
    private RoleService roleService;
    @RequestMapping("/findAllRole")
    public ResponseResult findAllUserByPage(@RequestBody Role role){
        List<Role> allRole = roleService.findAllRole(role);
        ResponseResult responseResult = new ResponseResult(true,200,"响应成
功",allRole);
        return responseResult;
    }
}

Postman测试接口

2.分配菜单

2.1 需求分析

需求:点击分配菜单,回显可选择菜单信息,并回显选中状态

image-20211206205914497

2.2 接口1 查询所有菜单列表

查看接口文档
Dao层:MenuMapper

public interface MenuMapper {
    /**
     * 查询全部的父子菜单信息
     * */
    public List<Menu> findSubMenuListByPid(int pid);
 
}
<!-- 一对多: 查找子孙菜单 -->
    <select id="findSubMenuListByPid" resultMap="MenuResult">
        select * from menu where parent_id = #{pid}
    </select>
    <!--  根据pid 查询所有子分类集合  -->
    <resultMap id="MenuResult" type="com.lagou.domain.Menu">
        <id column="id" property="id"></id>
        <result column="href" property="href"></result>
        <result column="icon" property="icon"></result>
        <result column="name" property="name"></result>
        <result column="parent_id" property="parentId"></result>
        <result column="description" property="description"></result>
        <result column="orderNum" property="order_num"></result>
        <result column="shown" property="shown"></result>
        <result column="created_time" property="createdTime"></result>
        <result column="updated_time" property="updatedTime"></result>
        <result column="created_by" property="createdBy"></result>
        <result column="updated_by" property="updatedBy"></result>
        <collection property="subMenuList" ofType="com.lagou.domain.Menu"
                    select="findSubMenuListByPid" column="id" ></collection>
    </resultMap>

Service层:MenuService

public interface MenuService {
    public List<Menu> findSubMenuListByPid(int pid);
}
@Service
public class MenuServiceImpl implements MenuService {
    @Autowired
    private MenuMapper menuMapper;
    @Override
    public List<Menu> findSubMenuListByPid(int pid) {
        List<Menu> menuList = menuMapper.findSubMenuListByPid(pid);
        return menuList;
    }
 }

Web层:RoleController

@RestController
@RequestMapping("/role")
public class RoleController {
    @Autowired
    private MenuService menuService;
/*
       查询所有菜单信息
    */
    @RequestMapping("/findAllMenu")
    public ResponseResult findAllMenu(){
        //-1 表示查询所有菜单数据
        List<Menu> menuList = menuService.findSubMenuListByPid(-1);
        Map<String,Object> map = new HashMap<>();
        map.put("parentMenuList",menuList);
        ResponseResult result = new ResponseResult(true,200,"响应成功",map);
        return result;
    }
}

Postman测试接口

2.3 接口2 根据角色ID查询关联菜单ID

Dao层:RoleMapperr

public interface RoleMapper {
    /*
        根据角色ID查询菜单信息
     */
    List<String> findMenuByRoleId(Integer roleId);
}
<mapper namespace="com.lagou.dao.RoleMapper">
    <!--  List<String> findMenuByRoleId(Integer roleId);-->
    <select id="findMenuByRoleId" parameterType="int" resultType="string">
        SELECT m.ìd`FROM roles r LEFT JOIN role_menu_relation  rm ON r.id = 
rm.`role_id`LEFT JOIN menu m ON rm.`menu_id` = m.ìd` WHERE r.id = #{id}
    </select>

Service层:RoleService

public interface RoleService {
        /**
          * 根据ID查询角色关联菜单
         * */
    List<String> findMenuByRoleId(Integer roleId);
}
@Service
public class RoleServiceImpl implements RoleService {
    @Autowired
    private RoleMapper roleMapper;
    @Override
    public List<String> findMenuByRoleId(Integer roleId) {
        List<String> list = roleMapper.findMenuByRoleId(roleId);
        return list;
    }
 }

Web层:RoleController

/**
     * 查询角色关联菜单列表ID
     * */
    @RequestMapping("/findMenuByRoleId")
    public ResponseResult findMenuByRoleId(Integer roleId){
        List<String> menuList = roleService.findMenuByRoleId(roleId);
        ResponseResult result = new ResponseResult(true,200,"响应成功",menuList);
        return result;
    }

Postman测试接口

2.4 接口3 为角色分配菜单列表

Dao层:RoleMapper

public interface RoleMapper {
    /*
        角色菜单关联
     */
    void RoleContextMenu(Role_menu_relation role_menu_relation);
}
<?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.lagou.dao.RoleMapper">
    
    <!--删除角色菜单关联信息-->
    <delete id="deleteRoleContextMenu" parameterType="int">
        delete from role_menu_relation where role_id = #{id}
    </delete>
     <!--角色菜单关联-->
    <insert id="RoleContextMenu" 
parameterType="com.lagou.domain.Role_menu_relation">
        insert into role_menu_relation values(null,#{menuId},#{roleId},#
{createdTime},#{updatedTime},#{createdBy},#{updatedby})
    </insert>
    
</mapper>

Service层:RoleService

public interface RoleService {
    void RoleContextMenu(RoleMenuVo roleMenuVo);
}
@Service
public class RoleServiceImpl implements RoleService {
    @Override
    public void RoleContextMenu(RoleMenuVo roleMenuVo) {
        // 清空中间表
        roleMapper.deleteRoleContextMenu(roleMenuVo.getRoleId());
        for (Integer mid : roleMenuVo.getMenuIdList()) {
            Role_menu_relation role_menu_relation = new Role_menu_relation();
            role_menu_relation.setRoleId(roleMenuVo.getRoleId());
            role_menu_relation.setMenuId(mid);
            role_menu_relation.setCreatedTime(new Date());
            role_menu_relation.setUpdatedTime(new Date());
            role_menu_relation.setCreatedBy("system");
            role_menu_relation.setUpdatedby("system");
            roleMapper.RoleContextMenu(role_menu_relation);
        }
    }
 }

Web层:RoleController

@RestController
@RequestMapping("/role")
public class RoleController {
    @Autowired
    private RoleService roleService;
    /*
        用户关联菜单 {roleId: 4, menuIdList: [19, 20, 7, 8, 9, 15, 16, 17, 18]}
     */
    @RequestMapping("/RoleContextMenu")
    public ResponseResult RoleContextMenu(@RequestBody RoleMenuVo roleMenuVo){
        roleService.RoleContextMenu(roleMenuVo);
        ResponseResult result = new ResponseResult(true,200,"响应成功","");
        return result;
    }
}

Postman测试接口

3.删除角色

3.1 需求分析

需求:点击删除按钮,将选中的角色信息删除

image-20211206210439092

3.2 查看接口文档,进行编码

查看接口文档

Dao层:RoleMapper

public interface RoleMapper {
    /*
        删除角色
     */
    void deleteRole(Integer id);
}
<?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.lagou.dao.RoleMapper">
      <delete id="deleteRole" parameterType="int">
        delete from roles where id = #{id}
    </delete>
</mapper>

Service层:RoleService

public interface RoleService {
    void deleteRole(Integer id);
}
@Service
public class RoleServiceImpl implements RoleService {
    @Autowired
    private RoleMapper roleMapper;
    @Override
    public void deleteRole(Integer id) {
         // 清空中间表
        roleMapper.deleteRoleContextMenu(id);
        roleMapper.deleteRole(id);
    }
 }

Web层:RoleController

@RestController
@RequestMapping("/role")
public class RoleController {
    @Autowired
    private RoleService roleService;
     /**
     * 删除角色
     * */
    @RequestMapping("/deleteRole")
    public ResponseResult deleteRole(Integer id){
        roleService.deleteRole(id);
        ResponseResult responseResult = new ResponseResult(true,200,"响应成
功","");
        return responseResult;
    }
}

Postman测试接口

五 权限管理(菜单模块)接口实现

1.菜单列表查询

1.1 需求分析

需求:点击菜单列表,对菜单信息进行列表展示

image-20211206210631938

1.2 查看接口文档,进行编码

查看接口文档
实体类:Menu

public class Menu {
       //主键id
    private Integer id;
    //父菜单id
    private int parentId;
    //菜单路径
    private String href;
    //菜单图标
    private String icon;
    //菜单名称
    private String name;
    //描述
    private String description;
    //排序号
    private int orderNum;
    //是否展示
    private int shown;
    //菜单层级,从0开始
    private int level;
    //创建时间
    private Date createdTime;
    //更新时间
    private Date updatedTime;
    //创建人
    private String createdBy;
    //更新人
    private String updatedBy;
    
    // getter/setter..
}

Dao层:MenuMapper

public interface MenuMapper {
    /**
     * 查询菜单列表
     * */
    public List<Menu> findAllMenu();
}
<mapper namespace="com.lagou.dao.MenuMapper">
    <!--  查询菜单列表  -->
    <select id="findAllMenu" resultType="com.lagou.domain.Menu">
        SELECT
            id,
            parent_id,
            href,
            icon,
            NAME,
            description,
            order_num,
            shown,
            LEVEL,
            created_time,
            updated_time,
            created_by,
            updated_by
        FROM menu
    </select>
</mapper>

Service层:MenuService

public interface MenuService {
    public List<Menu> findAllMenu();
}
@Service
public class MenuServiceImpl implements MenuService {
    @Autowired
    private MenuMapper menuMapper;
    @Override
    public List<Menu> findAllMenu() {
        List<Menu> list = menuMapper.findAllMenu();
        return list;
    }

Web层:MenuController

@RestController
@RequestMapping("/menu")
public class MenuController {
    @Autowired
    private MenuService menuService;
    /**
     * 查询菜单列表信息
     * */
    @RequestMapping("/findAllMenu")
    public ResponseResult findAllMenu(){
        List<Menu> list = menuService.findAllMenu();
        ResponseResult result = new ResponseResult(true,200,"响应成功",list);
        return result;
    }
}

Postman测试接口

2.查询菜单信息(回显)

2.1 需求分析

需求:点击添加菜单按钮,跳转到添加菜单页面,回显当前添加菜单可以选择的上级菜单信息

image-20211206210822559

2.2 查看接口文档,进行编码

查看接口文档
Dao层:MenuMapper

public interface MenuMapper {
 /**
     * 查询全部的父子菜单信息
     * */
    public List<Menu> findSubMenuListByPid(int pid);
}
<mapper namespace="com.lagou.dao.MenuMapper">
  <!-- 一对多: 查找子孙菜单 -->
  <select id="findSubMenuListByPid" resultMap="MenuResult">
        select * from menu where parent_id = #{pid}
    </select>
    <!--  根据pid 查询所有子分类集合  -->
    <resultMap id="MenuResult" type="com.lagou.domain.Menu">
        <id column="id" property="id"></id>
        <result column="href" property="href"></result>
        <result column="icon" property="icon"></result>
        <result column="name" property="name"></result>
        <result column="parent_id" property="parentId"></result>
        <result column="description" property="description"></result>
        <result column="orderNum" property="order_num"></result>
        <result column="shown" property="shown"></result>
        <result column="created_time" property="createdTime"></result>
        <result column="updated_time" property="updatedTime"></result>
        <result column="created_by" property="createdBy"></result>
        <result column="updated_by" property="updatedBy"></result>
        <collection property="subMenuList" ofType="com.lagou.domain.Menu"
                    select="findSubMenuListByPid" column="id" ></collection>
    </resultMap>
</mapper>

Service层:MenuService

public interface MenuService {
    public List<Menu> findSubMenuListByPid(int pid);
}
@Service
public class MenuServiceImpl implements MenuService {
    @Autowired
    private MenuMapper menuMapper;
  @Override
    public List<Menu> findSubMenuListByPid(int pid) {
        List<Menu> menuList = menuMapper.findSubMenuListByPid(pid);
        return menuList;
    }
}

Web层:MenuController

@RestController
@RequestMapping("/menu")
public class MenuController {
    @Autowired
    private MenuService menuService;
   /**
     * 回显菜单信息(包括父子菜单的全部信息)
     * */
    @RequestMapping("/findMenuInfoById")
    public ResponseResult findMenuInfoById(@RequestParam int id){
        if(id == -1){
            //添加操作 回显不需要查询 menu信息
            List<Menu> menuList = menuService.findSubMenuListByPid(-1);
            //封装数据
            Map<String,Object> map = new HashMap<>();
            map.put("menuInfo",null);
            map.put("parentMenuList",menuList);
            ResponseResult result = new ResponseResult(true,200,"响应成功",map);
            return result;
        }else{
            //修改操作 回显
            Menu menu = menuService.findMenuById(id);
            List<Menu> menuList = menuService.findSubMenuListByPid(-1);
            Map<String,Object> map = new HashMap<>();
            map.put("menuInfo",menu);
            map.put("parentMenuList",menuList);
            ResponseResult result = new ResponseResult(true,200,"响应成功",map);
            return result;
        }
    }
}

Postman测试接口

六 权限管理(资源模块)接口实现

1.资源分页&多条件查询

1.1 需求分析

需求:资源列表及多条件组合查询

image-20211206211002307

1.2 查看接口文档,进行编码

查看接口文档

Dao层:ResourceMapper

public interface ResourceMapper {
    public List<Resource> findAllResource(ResourceVo resourceVo);
}
<?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.lagou.dao.ResourceMapper">
    <!--查询所有资源-->
    <select id="findAllResource" resultType="com.lagou.domain.Resource">
        select * from resource
        <where>
            <if test="name != null">
                and name like  concat('%',#{name},'%')
            </if>
            <if test="url != null">
                and url = url
            </if>
            <if test="categoryId != null">
                and category_id = #{categoryId}
            </if>
        </where>
    </select>
</mapper>

Service层:ResourceService

public interface ResourceService {
    public PageInfo<Resource> findAllResource(ResourceVo resourceVo);
}
@Service
public class ResourceServiceImpl implements ResourceService {
    @Autowired
    private ResourceMapper resourceMapper;
    @Override
    public PageInfo<Resource> findAllResource(ResourceVo resourceVo) {
       
 PageHelper.startPage(resourceVo.getCurrentPage(),resourceVo.getPageSize());
        List<Resource> allResource = resourceMapper.findAllResource(resourceVo);
        PageInfo<Resource> adPageInfo = new PageInfo<Resource>(allResource);
        return adPageInfo;
    }

Web层:ResourceController

@RestController
@RequestMapping("/resource")
public class ResourceController {
    @Autowired
    private ResourceService resourceService;
    /**
     * 分页与条件查询
     * */
    @RequestMapping("/findAllResource")
    public ResponseResult findAllResource(@RequestBody ResourceVo resourceVo){
        PageInfo<Resource> allResource = 
resourceService.findAllResource(resourceVo);
        ResponseResult responseResult = new ResponseResult(true,200,"响应成
功",allResource);
        return responseResult;
    }
}

Postman测试接口

七 登陆及动态菜单展示

1.登陆

1.1 需求分析

需求:输入用户名密码,点击登陆按钮,进行用户登陆

image-20211206211138999

加密算法MD5介绍

1、什么是MD5

MD5加密全程是Message-Digest Algoorithm 5(信息-摘要算法),它对信息进行摘要采集,再通过一定的位运算,最终获取加密后的MD5字符串。

2、MD5有哪些特点

MD5加密的特点主要有以下几点:

1、针对不同长度待加密的数据、字符串等等,其都可以返回一个固定长度的MD5加密字符串(通常32位的16进制字符串)

2、其加密过程几乎不可逆除非维护一个庞大的Key-Value数据库来进行碰撞破解,否则几乎无法解开。

3、运算简便,且可实现方式多样,通过一定的处理方式也可以避免碰撞算法的破解。(加盐:随机字符串

4、对于一个固定的字符串。数字等等,MD5加密后的字符串是固定的也就是说不管MD5加密多少次,都是同样的结果

3、Java代码中如何使用MD5

(1)添加依赖

<!--MD5依赖-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.3.2</version>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.3</version>
        </dependency>

(2)添加工具类

public class Md5 {
    public final static  String md5key = "Ms2";
    /**
     * MD5方法
     * @param text 明文
     * @param key 密钥
     * @return 密文
     * @throws Exception
     */
    public static String md5(String text, String key) throws Exception {
        //加密后的字符串
        String encodeStr= DigestUtils.md5Hex(text+key);
        System.out.println("MD5加密后的字符串为:encodeStr="+encodeStr);
        return encodeStr;
    }
    /**
     * MD5验证方法
     * @param text 明文
     * @param key 密钥
     * @param md5 密文
     * @return true/false
     * @throws Exception
     */
    public static boolean verify(String text, String key, String md5) throws 
Exception {
        //根据传入的密钥进行验证
        String md5Text = md5(text, key);
        if(md5Text.equalsIgnoreCase(md5))
        {
            System.out.println("MD5验证通过");
            return true;
        }
        return false;
        }
    public static void main(String[] args) throws Exception {
        // 注册  用户名:tom  密码  123456
        // 添加用户的时候,要进行加密
        String lagou = Md5.md5("123456", "lagou");
        System.out.println(lagou);
        // 登陆  用户名 tom   123456 select * from user where username = tom and 
password = 123456
        // 1.根据用户名进行查询 f00485441dfb815c75a13f3c3389c0b9
        boolean verify = Md5.verify("123456", "lagou", 
"f00485441dfb815c75a13f3c3389c0b9");
        System.out.println(verify);
    }
}

1.2 查看接口文档,进行编码

查看接口文档

Dao层:UserMapper

public interface UserMapper  {
    /*
        用户登陆
     */
    public User login(User user);   
}
<?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.lagou.dao.UserMapper">
  <!-- 用户登陆 -->
    <select id="login" parameterType="com.lagou.domain.User" 
resultType="com.lagou.domain.User">
            select * from user where phone = #{phone} 
    </select>
</mapper>

Service层:UserService

public interface UserService {
    /*
         用户登录
     */
     public User login(User user);
}
@Service
public class UserServiceImpl implements UserService {
    
    @Autowired
    private UserMapper userMapper;
    /**
    * 用户登录
     * */
        @Override
    public User login(User user) throws Exception {
        User user2 = userMapper.login(user);
        if(user2 != null && 
Md5.verify(user.getPassword(),"lagou",user2.getPassword())){
            return user2;
        }else {
            return null;
        }
    }
 }

Web层:UserControlle

@RestController
@RequestMapping("/user")
public class UserController {
    
    @Autowired
    private UserService userService;
    
        /**
     * 用户登录
     * */
    @RequestMapping("/login")
    public ResponseResult login(User user, HttpServletRequest request) throws 
Exception {
        User login = userService.login(user);
        ResponseResult result = null;
        if(login !=null ){
        //保存access_token
            Map<String,Object> map = new HashMap<>();
            String  access_token = UUID.randomUUID().toString();
            map.put("access_token", access_token);
            map.put("user_id",login.getId());
            HttpSession session = request.getSession();
            session.setAttribute("user_id",login.getId());
            session.setAttribute("access_token",access_token);
             result = new ResponseResult(true,1,"响应成功",map);
        }else{
             result = new ResponseResult(true,1,"用户名密码错误",null);
        }
        return result;
    }
}

Postman测试接口

2.分配角色(回显)

2.1 需求分析

需求:点击分配角色,将该用户所具有的角色信息进行回显

image-20211206211753150

2.2 查看接口文档,进行编码

查看接口文档
Dao层:UserMapper

public interface UserMapper {
    /**
     * 根据ID查询用户当前角色
     * */
    public List<Role> findUserRelationRoleById(int id);
}
<?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.lagou.dao.UserMapper">
     <!-- 根据ID查询用户当前角色   -->
    <select id="findUserRelationRoleById" resultType="com.lagou.domain.Role" 
parameterType="int">
        SELECT
            r.id,
            r.code,
            r.name,
            r.description
        FROM roles r INNER JOIN user_role_relation ur
        ON r.ìd` = ur.`role_idÌNNER JOIN USER u ON ur.ùser_id` = u.ìd`
        WHERE u.ìd` = #{id}
    </select>
   
</mapper>

Service层:UserService

public interface UserService {
    /**
     * 获取用户拥有的角色
     * */
    public List<Role> findUserRelationRoleById(int id) ;
}
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    /**
     * 获取用户拥有的角色
     * */
    @Override
    public List<Role> findUserRelationRoleById(int id) {
    List<Role> roleList = userMapper.findUserRelationRoleById(id);
        return roleList;
    }
 }

Web层:UserController

@RestController
@RequestMapping("/user")
public class UserController {
     @Autowired
    private UserService userService;
    /*
    获取用户拥有的角色
     */
    @RequestMapping("/findUserRoleById")
    public ResponseResult findUserRoleById(int id){
        List<Role> roleList = userService.findUserRelationRoleById(id);
        return  new ResponseResult(true,200,"分配角色回显成功",roleList);
    }
}

Postman测试接口

3分配角色

3.1 需求分析

需求:点击确定按钮,真正实现用户角色关联

image-20211206211934818

image-20211206211940802

3.2 查看接口文档,进行编码

查看接口文档
Dao层:UserMapper

public interface UserMapper {
       /*
        根据用户ID清空中间表
     */
    void deleteUserContextRole(Integer userId);
    /*
        分配角色
     */
    void userContextRole(User_Role_relation user_role_relation);
}
<?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.lagou.dao.UserMapper">
    <!-- 根据userid清空中间表关联关系     void deleteUserContextRole(Integer 
userId);-->
    <delete id="deleteUserContextRole" parameterType="int">
        delete from  user_role_relation where user_id = #{userid}
    </delete>
    <!--用户角色关联     void userContextRole(Integer userId, Integer roleid);-->
    <insert id="userContextRole" 
 parameterType="com.lagou.domain.User_Role_relation">
        insert into user_role_relation values(null,#{userId},#{roleId},#{createdTime},#{updatedTime},
        #{createdBy},#{updatedby})
    </insert>
</mapper>

Service层:UserService

public interface UserService {
       /*
         用户关联角色
        */
    void userContextRole(UserVo userVo);
}
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    /*
        用户关联角色
     */
    @Override
    public void userContextRole(UserVo userVo) {
        // 根据用户ID清空中间表的关联关系
        userMapper.deleteUserContextRole(userVo.getUserId());
        // 向中间表添加记录
        for (Integer roleid : userVo.getRoleIdList()) {
            User_Role_relation user_role_relation = new User_Role_relation();
            user_role_relation.setUserId(userVo.getUserId());
            user_role_relation.setRoleId(roleid);
            Date date = new Date();
            user_role_relation.setCreatedTime(date);
            user_role_relation.setUpdatedTime(date);
            user_role_relation.setCreatedBy("system");
            user_role_relation.setUpdatedby("system");
            
            userMapper.userContextRole(user_role_relation);
        }
    }
 }

Web层:UserController

@RestController
@RequestMapping("/user")
public class UserController {
     @Autowired
     private UserService userService;
       /*
            分配角色
       */
    @RequestMapping("/userContextRole")
    public ResponseResult userContextRole(@RequestBody UserVo userVo){
        userService.userContextRole(userVo);
        return  new ResponseResult(true,200,"分配角色成功",null);
    }
}

Postman测试接口

4.动态菜单显示

4.1 需求分析

需求:登陆成功后,根据用户所拥有的权限信息,进行菜单列表动态展示

image-20211206212138068

4.2 查看接口文档,进行编码

查看接口文档
Dao层:UserMapper

public interface UserMapper {
    /**
     * 根据ID查询用户当前角色
     * */
    public List<Role> findUserRelationRoleById(int id);
    /**
     * 根据角色id,查询角色拥有的顶级菜单信息
     * */
    public List<Menu> findParentMenuByRoleId(List<Integer> ids);
    /**
     * 根据PID 查询子菜单信息
     * */
    public List<Menu> findSubMenuByPid(int pid);
    /**
     * 获取用户拥有的资源权限信息
     * */
    public List<Resource> findResourceByRoleId(List<Integer> ids);
    
}
<?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.lagou.dao.UserMapper">
     <!-- 根据ID查询用户当前角色   -->
    <select id="findUserRelationRoleById" resultType="com.lagou.domain.Role" 
parameterType="int">
        SELECT
            r.id,
            r.code,
            r.name,
            r.description
        FROM roles r INNER JOIN user_role_relation ur
        ON r.ìd` = ur.`role_idÌNNER JOIN USER u ON ur.ùser_id` = u.ìd`
        WHERE u.ìd` = #{id}
    </select>
    <!--  根据角色id,查询角色拥有的顶级菜单信息  -->
    <select id="findParentMenuByRoleId" parameterType="java.util.List" resultType="com.lagou.domain.Menu">
          SELECT
             DISTINCT  m.*
         FROM roles r INNER JOIN role_menu_relation rm ON r.ìd` = rm.role_id
                INNER JOIN menu m ON rm.menu_id = m.id
                 WHERE m.parent_id = -1 AND r.id IN 
           <foreach  collection="list" item="item"  open="(" separator="," close=")">
                #{item}
         </foreach>
          GROUP BY m.id
    </select>
    <!-- 根据PID 查找子菜单 -->
    <select id="findSubMenuByPid" resultType="com.lagou.domain.Menu">
    select * from menu where parent_id = #{pid}
    </select>
    <!--  获取用户拥有的资源权限  -->
    <select id="findResourceByRoleId" parameterType="java.util.List" resultType="com.lagou.domain.Resource">
                SELECT
          DISTINCT rc.*
        FROM roles r  INNER JOIN role_resource_relation rrr ON r.ìd` = rrr.`role_id`
        INNER JOIN resource rc ON rrr.`resource_id` = rc.ìd` WHERE r.id IN 
        <foreach item="item" index="index" collection="list" open="(" separator="," close=")">
            #{item}
        </foreach>
        GROUP BY rc.id;
    </select>
</mapper>

Service层:UserService

public interface UserService {
          /*
            * 获取用户权限
         * */
       ResponseResult getUserPermissions(Integer id);
}
@Service
public class UserServiceImpl implements PromotionSpaceService {
   @Autowired
    private UserMapper userMapper;
    @Override
    public ResponseResult getUserPermissions(Integer id) {
        //1.获取当前用户拥有的角色
        List<Role> roleList = userMapper.findUserRelationRoleById(id);
        //2.获取角色ID,保存到 list
        List<Integer> list = new ArrayList<>();
        for (Role role : roleList) {
            list.add(role.getId());
        }
        //3.根据角色id查询 父菜单
        List<Menu> parentMenu = userMapper.findParentMenuByRoleId(list);
        //4.封装父菜单下的子菜单
        for (Menu menu : parentMenu) {
            List<Menu> subMenu = userMapper.findSubMenuByPid(menu.getId());
            menu.setSubMenuList(subMenu);
        }
        //5.获取资源权限
        List<Resource> resourceList = userMapper.findResourceByRoleId(list);
        //6.封装数据
        Map<String,Object> map = new HashMap<>();
        map.put("menuList",parentMenu);  //menuList: 菜单权限数据
        map.put("resourceList",resourceList);//resourceList: 资源权限数据
        ResponseResult result = new ResponseResult(true,200,"响应成功",map);
        return result;
    }
 }

Web层:UserController

@RestController
@RequestMapping("/user")
public class UserController {
     @Autowired
    private UserService userService;
    /**
     * 获取用户权限
     * */
    @RequestMapping("/getUserPermissions")
    public ResponseResult getUserPermissions(HttpServletRequest request){
        //获取请求头中的 token
        String token = request.getHeader("Authorization");
        //获取session中的access_token
        HttpSession session = request.getSession();
        String access_token = (String)session.getAttribute("access_token");
        //判断
        if(token.equals(access_token)){
            int user_id = (Integer)session.getAttribute("user_id");
            ResponseResult result = userService.getUserPermissions(user_id);
            return result;
        }else{
            ResponseResult result = new ResponseResult(false,400,"获取失败","");
            return result;
        }
    }
}

Postman测试接口

posted on 2021-12-11 09:10  寒露凝珠  阅读(250)  评论(0编辑  收藏  举报

导航