项目实战后续(课程管理模块)
项目介绍:
前面我们完成了初步的项目,接下来实现更高等级的作用(基于框架的项目编写)
页面原型展示:
技术选型:
前端技术选型:
后端技术选型:
项目开发环境 :
开发工具:
后端:IDEA 2019
前端:VS code
数据库客户端工具: SQLYog
开发环境:
JDK 11
Maven 3.6.3
idea自带maven,但一般不使用,因为对应仓库默认放在c盘的,若你使用也没有问题
只是自己配置的有利于理解,且自己配置的基本可以设置仓库路径
idea自带的很难设置仓库路径,或者不可以设置,除非更改更加底层的配置(也可以说是文件),或者代码
MySQL 5.7
Maven进阶使用(Maven聚合工程) :
maven基础知识回顾 :
maven介绍
maven 是一个项目管理工具,主要作用是在项目开发阶段对Java项目进行依赖管理和项目构建
依赖管理:就是对jar包的管理,通过导入maven坐标,就相当于将仓库中的jar包导入了当前项目中
项目构建:通过maven的一个命令就可以完成项目从清理、编译、测试、报告、打包,部署整个过程
maven的仓库类型:
本地仓库
远程仓库
maven中央仓库(地址:http://repo2.maven.org/maven2/)
maven私服(公司局域网内的仓库,需要自己搭建)
其他公共远程仓库(例如apache提供的远程仓库,地址:http://repo.maven.apache.org/maven2/)
本地仓库—》maven私服—》maven中央仓库(若改变了则使用改变的远程仓库)
maven常用命令:
clean: 清理
compile:编译
test: 测试
package:打包
install: 安装,将项目打包的jar包放入仓库里面
maven坐标书写规范:
Maven的仓库搭建:
Maven软件的下载
使用 Maven 管理工具,我们首先要到官网去下载它的安装软件
版本自行选择
Maven 下载后,将 Maven 解压到一个没有中文没有空格的路径下,比如:H:\software\maven 下面
解压后目录结构如下:
bin:存放了 maven 的命令
boot:存放了一些 maven 本身的引导程序,如类加载器等
conf:存放了 maven 的一些配置文件,如 setting.xml 文件
lib:存放了 maven 本身运行所需的一些 jar 包
Maven环境变量配置:
配置 MAVEN_HOME ,变量值就是你的 maven 安装的路径(bin 目录之前一级目录)
将MAVEN_HOME 添加到Path系统变量:
Maven 软件版本测试 :
通过 mvn -v命令检查 maven 是否安装成功
看到 maven 的版本为 3.6.3 及 java 版本为 jdk-11 即为安装 成功
打开命令行,输入 mvn –v命令(配置了环境变量,那么可以任意位置了),如下图:
Maven 仓库:
Maven中的仓库是用来存放maven构建的项目和各种依赖的(Jar包)
本地仓库:位于自己计算机中的仓库, 用来存储从远程仓库或中央仓库下载的插件和 jar 包,
远程仓库:需要联网才可以使用的仓库,阿里提供了一个免费的maven 远程仓库。
中央仓库(默认的远程仓库,所以通常叫做中央仓库):在 maven 软件中内置一个远程仓库地址 http://repo1.maven.org/maven2
它是中央仓库,服务于整个互联网,它是由 Maven 团队自己维护,里面存储了非常全的 jar 包
它包含了世界上大部分流行的开源项目构件
Maven 本地仓库的配置 :
maven仓库默认是在 C盘 .m2 目录下,我们最好不要将仓库放在C盘(除非c盘足够大)
我们可以创建一个目录用来存放这些jar包,如H:\software\repository 目录
在maven安装目录中,进入 conf文件夹,可以看到一个 settings.xml 文件中,我们在这个文件中,进行本地仓库的配置
打开 settings.xml文件,进行如下配置如下:
指定的路径,就是我们创建的存放jar的目录文件
配置阿里云远程仓库:
Maven默认的远程仓库是在国外,所以下载jar包时速度会非常慢,这里推荐大家使用我大天朝的阿里云仓库
打开 settings.xml,找到 < mirrors> 标签 , 下面的内容复制到 < mirrors> 中 即可
< mirror>
< id> alimaven</ id>
< name> aliyun maven</ name>
< url>
http://maven.aliyun.com/nexus/content/groups/public/
</ url>
< mirrorOf> central</ mirrorOf>
</ mirror>
以上就是配置仓库的步骤
maven的依赖传递 :
什么是依赖传递 :
在maven中,依赖是可以传递的,假设存在三个项目,分别是项目A,项目B以及项目C
假设C依赖B,B依赖A,那么我们可以根据maven项目依赖的特征不难推出项目C也依赖A,即依赖传递
即项目C既可以用到项目B中的资源,也可以用到项目A中的资源,xml读取时有先后顺序,后面会说明
注意:他们的传递等级划分是对应父子工程来的,真正的jar包没有等级划分,这句话在后面说明时,及其重要
注意:在maven中,使用< packaging >war</ packaging >注意指定自己下载的maven
idea默认的maven操作不了(除非设置一些编译,百度可以找到)
导入依赖:
< dependencies>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-webmvc</ artifactId>
< version> 5.1.5.RELEASE</ version>
</ dependency>
下面是pom.xml导入jar包时(spring-webmvc包),根据依赖传递,从而进行自动导入的其他依赖包
所以发现,除了spring-webmvc包,还有其他包
当然,在项目里面都是同一级,而maven里显示包依赖级别,但都是一种显示方式
项目显示(真正的jar包没有等级划分):
maven级别显示(等级划分,父子工程的划分):
由于我们导入依赖时,是指定项目的,即< artifactId>spring-webmvc</ artifactId>,artifactId是定义实际项目名称
那么我们前面说的,maven导入jar依赖包,实际上是通过maven来获得其项目的对应jar包
所以一般就称作导入依赖或者导入某某(项目)依赖(项目之间的依赖),依赖也可以叫做jar包或者获取jar包
也可以将项目名称叫做依赖
当我们导入依赖时,就可能会出现依赖传递
图解:
通过上面的图可以看到,我们的web项目直接依赖了spring-webmvc(没有标明spring-jcl,但也是依赖传递,即间接依赖)
而spring-webmvc依赖了sping-aop、spring-beans等
最终的结果就是在我们的web项目中间接依赖了spring-aop、spring-beans等
依赖冲突:
如下:
< dependencies>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-webmvc</ artifactId>
< version> 5.1.5.RELEASE</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-aop</ artifactId>
< version> 5.1.6.RELEASE</ version>
</ dependency>
</ dependencies>
我们在spring-webmvc的基础上添加spring-aop
图解:
由于依赖传递现象的存在, spring-webmvc 依赖 spirng-beans-5.1.5,spring-aop 依赖 springbeans-5.1.6
但是发现spirng-beans-5.1.5 加入到了工程中
因为对应spring-webmvc在前面,按照先后顺序作为对应包,需要是同一等级的依赖,如他们都是对应第二等级的依赖
而我们希望 spring-beans-5.1.6 加入工程
这就造成了依赖冲突(一般不知道会造成冲突,所以也就是通常放在后面,使得对应包不起作用)
依赖冲突:一般的有些操作需要对应版本,否则可能会报错,假如某些操作不支持对应包的5.1.5版本,而支持5.1.6版本
而我们导入对应包的5.1.6版本时,放在后面,使得明明加入了对应版本,任然使得不支持了,即可能会报错
或者导入的对应包放前面覆盖了后面对应依赖jar包,而这个导入的我们不支持,即也可能会报错
这就是依赖冲突的出现方式(主要是前面一种,因为一般我们都只将导入的依赖jar包位置,放在后面,而不是前面)
注意:这里非常重要,他们的操作依赖的传递,而不是单独的放在pom.xml里面,所以是上面的作用
但是,若都是在pom.xml里面,则后面的覆盖前面的,而不是前面的覆盖后面的,这里要记住,正是因为在pom.xml只有该一点
所以这里说的,基本都是依赖的传递,即后面也是如此
如何解决依赖冲突:
在前面虽然说明真正的jar包没有等级划分,但是读取顺序由xml决定,之后才没有等级划分
使用maven提供的依赖调解原则(xml读取顺序,同样的后面就不读取了) :
第一声明者优先原则(优先原则,一般是相同的等级来使用这个原则)
路径近者优先原则(高等级优先,如上面的spring-aop是5.1.6版本,而不是5.1.5版本
排除依赖操作
锁定版本操作
这都是maven规定的原则,也就是说,在获得jar包后,先不导入
而是先根据这个原则进行操作,然后一次性全部导入
依赖调节原则——第一声明者优先原则:
在 pom 文件中定义依赖,以先声明的依赖为准
其实就是根据坐标导入的顺序来确定最终使用哪个传递过来的依赖
结论:通过上图可以看到,spring-aop和spring-webmvc都传递过来了spring-beans,但是因为spring-aop在前面
所以最终使用的spring-beans是由spring-aop传递过来的,而spring-webmvc传递过来的spring-beans则被忽略了(但还是被导入的,所以当我们不需要他占用资源时,一般操作排除)
依赖调节原则——路径近者优先原则:
总结:直接依赖大于依赖传递
排除依赖:
可以使用exclusions标签将传递过来的依赖排除出去
最后补充:一般直接依赖>父依赖>子依赖,在相同时,那么操作如上
所以如果父依赖有对应的信息,那么无论是多少层级,一般操作父依赖
版本锁定(一般使用这个方式来解决依赖冲突):
采用直接锁定版本的方法确定依赖jar包的版本,版本锁定后则不考虑依赖的声明顺序或依赖的路径
以锁定的版本为准添加到工程中,但不会锁定已经在maven存在的依赖,即一级直接依赖(写在pom.xml里的)
所以当锁定的依赖与一级直接依赖一样时,一级直接依赖为主(有版本的情况下)
即相当于版本锁定失效,但是若一级直接依赖没有指定版本
那么这个版本锁定就会起作用,即使用版本锁定的那个版本,此方法在企业开发中经常使用
dependencyManagement中定义的只是依赖的声明,并不实现引入,所以还是需要我们写上依赖,通常dependencyManagement操作版本,是在Spring Boot项目中操作依赖管理的主要角色
版本锁定的使用方式:
第一步:在dependencyManagement标签中锁定依赖的版本,且该标签只能存在一个,否则基本报错
第二步:在dependencies标签中声明需要导入的maven坐标
在dependencyManagement标签中锁定依赖的版本:
在dependencies标签中声明需要导入的maven坐标:
properties标签的使用:
< properties>
< spring.version> 5.1.4.RELEASE</ spring.version>
</ properties>
< dependencyManagement>
< dependencies>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-beans</ artifactId>
< version> ${spring.version}</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-context</ artifactId>
< version> ${spring.version}</ version>
</ dependency>
</ dependencies>
</ dependencyManagement>
maven聚合工程(分模块,主要作用是一个命令全部操作) :
概念:
在现实生活中,汽车厂家进行汽车生产时,由于整个生产过程非常复杂和繁琐,工作量非常大
所以厂家都会将整个汽车的部件分开生产,最终再将生产好的部件进行组装,形成一台完整的汽车
分模块构建maven工程分析 :
在企业项目开发中,由于项目规模大,业务复杂,参与的人员比较多
一般会通过合理的模块拆分将一个大型的项目拆分为N多个小模块,分别进行开发
而且拆分出的模块可以非常容易的被其他模块复用
常见的拆分方式有两种:
第一种:按照业务模块进行拆分,每个模块拆分成一个maven工程
例如将一个项目分为用户模块,订单模块,购物车模块等,每个模块对应就是一个maven工程
第二种:按照层进行拆分,例如持久层、业务层、表现层等,每个层对应就是一个maven工程
不管上面那种拆分方式,通常都会提供一个父工程,将一些公共的代码和配置提取到父工程中进行统一管理和配置
maven工程的继承:
首先我们也要注意,工程实际上也是文件夹,只是idea让他有对应作用而已
在Java语言中,类之间是可以继承的,通过继承,子类就可以引用父类中非private的属性和方法
同样,在maven工程之间也可以继承,子工程继承父工程后,就可以使用在父工程中引入的依赖
继承的目的是为了消除重复代码
结构如下:
父工程pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
< project xmlns = " http://maven.apache.org/POM/4.0.0"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-
4.0.0.xsd" >
< modelVersion> 4.0.0</ modelVersion>
< groupId> com.lagou</ groupId>
< artifactId> maven_parent</ artifactId>
< version> 1.0-SNAPSHOT</ version>
< modules>
< module> maven_children</ module>
< module> ../s</ module>
</ modules>
< properties>
< maven.compiler.source> 11</ maven.compiler.source>
< maven.compiler.target> 11</ maven.compiler.target>
</ properties>
< packaging> pom</ packaging>
< dependencies>
< dependency>
< groupId> org.mybatis</ groupId>
< artifactId> mybatis</ artifactId>
< version> 3.5.5</ version>
</ dependency>
</ dependencies>
</ project>
子工程pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
< project xmlns = " http://maven.apache.org/POM/4.0.0"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-
4.0.0.xsd" >
< parent>
< artifactId> maven_parent</ artifactId>
< groupId> com.lagou</ groupId>
< version> 1.0-SNAPSHOT</ version>
</ parent>
< modelVersion> 4.0.0</ modelVersion>
< artifactId> maven_children</ artifactId>
< properties>
< maven.compiler.source> 11</ maven.compiler.source>
< maven.compiler.target> 11</ maven.compiler.target>
</ properties>
</ project>
我们创建子工程方法,一般如下:
发现,上面指定了对应父工程,这样创建后,就会到该父工程里(前提路径要正确),即
这样路径要在对应父目录下,否则就是这样的,看如下:
<?xml version="1.0" encoding="UTF-8"?>
< project xmlns = " http://maven.apache.org/POM/4.0.0"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-
4.0.0.xsd" >
< parent>
< artifactId> maven_parent</ artifactId>
< groupId> com.lagou</ groupId>
< version> 1.0-SNAPSHOT</ version>
< relativePath> ../maven_parent/pom.xml</ relativePath>
</ parent>
< modelVersion> 4.0.0</ modelVersion>
< artifactId> s</ artifactId>
< properties>
< maven.compiler.source> 11</ maven.compiler.source>
< maven.compiler.target> 11</ maven.compiler.target>
</ properties>
</ project>
当然,父子工程中,相同的包有多个的,也就是说,从父得到的相当于复制一份,当然,内容也是(其实内部是模块的知识,说成是idea操作的也行(包括依赖))
最后打包时,才会统一
我们在父工程里添加如下配置:
< dependencies>
< dependency>
< groupId> org.mybatis</ groupId>
< artifactId> mybatis</ artifactId>
< version> 3.5.5</ version>
</ dependency>
</ dependencies>
配置刷新后,看如图
发现子工程也有对应依赖了,因为也是使用着父工程的pom.xml的,所以父工程pom.xml刷新使用后,也会对子工程进行操作
依次类推,子工程也可以当父工程,使得他的pom.xml导入的包,可以被他的子工程获得,但是不会让父工程获得
也就是说,父工程先进行导入jar包,然后子工程导入父工程的jar包,当然了子工程之间的jar包的传递
一般需要对应的子工程的打包,使得可以去仓库里获得
而这样的,实际上我们操作了很多次,比如上面的导入代码,先看图,再看代码
可以发现指定了对应Maven组织名称,通常是公司名(com.lagou)
指定了项目名称,这里是untitled
指定了对应版本,这里是1.0-SNAPSHOT
那么接下来看代码:
< dependencies>
< dependency>
< groupId> org.mybatis</ groupId>
< artifactId> mybatis</ artifactId>
< version> 3.5.5</ version>
</ dependency>
</ dependencies>
< parent>
< artifactId> maven_parent</ artifactId>
< groupId> com.lagou</ groupId>
< version> 1.0-SNAPSHOT</ version>
</ parent>
注意:maven的刷新,是所有工程的pom.xml刷新
maven工程的聚合:
在maven工程的pom.xml文件中可以使用标签将其他maven工程聚合到一起,聚合的目的是为了进行统一操作
例如拆分后的maven工程有多个,如果要进行打包,就需要针对每个工程分别执行打包命令,操作起来非常繁琐
这时就可以使用标签将这些工程统一聚合到maven父工程中,需要打包的时候
只需要在此工程中执行一次打包命令,其下被聚合的工程就都会被打包了(会根据对应的项目依赖来进行打包顺序)
如进行聚合操作时,dependencies标签里的对应项目没有他的jar包,那么就会等待,直到出现才进行安装打包
若最后不存在,则报错
而一些打包命令,如mvn install命令,必须是有对应包存在才可进行操作,否则报错,所有命令和dependencies是有区别的
命令只操作项目打包的jar包,而dependencies操作仓库以及本maven工程的jar包
上面的解释:
这里还需要注意一点:导入的依赖或者说包,若该包中的类与你自己的类名冲突(包括包路径的),编译器会使用当前作用域中定义的类,而不是导入的类,这可能导致导入的类被隐藏,不会直接导致冲突报错(这个隐藏是特殊的,是idea处理时的隐藏,或者编译器自身的其他作用导致,了解即可)
maven聚合工程:
工程整体结构如下:
lagou_edu_home_parent为父工程,其余工程为子工程,都继承父工程lagou_edu_home_parent
lagou_edu_home_parent工程将其子工程都进行了聚合
子工程之间存在依赖关系:
ssm_domain依赖ssm_utils
ssm_dao依赖ssm_domain
ssm_service依赖ssm_dao
ssm_web依赖ssm_service
图解:
直接依赖就是对应模块的使用mvn install命令后,出现的jar包,即其他模块导入时,就可以使用这些类了
注意:jar包一般存放的是class文件,以及一些资源
查看方式:将jar后缀名改成zip,然后解压,那么就可以看到对应的内容了
注意:创建时需要指定名称,也就是Location这个地方
否则直接的存在的名称和名称/会有别名,当然指定路径有不存在的,那么就会创建出来
最后:我们可以发现pom.xml实际上也是被读取而设置的配置文件(由maven读取),使得通过内容进行依赖的操作
实际上idea这个软件的设置是一般是操作我们目录的.idea的配置文件的,因为idea软件也只是给我们进行方便操作罢了
根据图片进行父子工程模块的创建以及对应依赖编写:
父工程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>
< dependencyManagement>
< dependencies>
< dependency>
< groupId> org.mybatis</ groupId>
< artifactId> mybatis</ artifactId>
< version> ${mybatis.version}</ version>
</ dependency>
< dependency>
< groupId> org.springframework</ groupId>
< artifactId> spring-webmvc</ artifactId>
< version> ${springmvc.version}</ version>
</ dependency>
< 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>
< 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>
< 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>
< dependency>
< groupId> org.mybatis</ groupId>
< artifactId> mybatis-spring</ artifactId>
< version> 1.3.1</ version>
</ dependency>
< 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>
< 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>
继承的jar包是第一点五等级级别,低于第一级别,高于第二级别
子工程ssm_utils构建 :
用来存放工具类的代码
子工程ssm_utils依赖基本不用操作编写,因为基本用来被其他工程导入
子工程ssm_domain构建:
用来存放实体类的代码
配置ssm_domain工程的pom.xml文件:
< dependencies>
< dependency>
< groupId> com.lagou</ groupId>
< artifactId> ssm_utils</ artifactId>
< version> 1.0-SNAPSHOT</ version>
</ dependency>
</ dependencies>
实体类:
package com. lagou. domain ;
public class Test {
private Integer id;
private String name;
@Override
public String toString ( ) {
return "Text{" +
"id=" + id +
", name='" + name + '\'' +
'}' ;
}
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;
}
}
子工程ssm_dao构建:
用来存放Dao层的代码,也就是数据库相关代码
配置ssm_dao工程的pom.xml文件:
< dependencies>
< dependency>
< groupId> com.lagou</ groupId>
< artifactId> ssm_domain</ artifactId>
< version> 1.0-SNAPSHOT</ version>
</ dependency>
</ dependencies>
dao接口:
package com. lagou. dao ;
import com. lagou. domain. Test ;
import java. util. List ;
public interface TestMapper {
public List < Test > findAllTest ( ) ;
}
创建DAO接口和Mapper映射文件:
<?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,后面加上了-dao
这样做,是为了防止jar包同名,使得不起作用,因为优先加载当前的配置,所以加载后,对应jar包同名的就不加载了
我们可以理解为,导入jar包,就是将对应的包文件放入我们的对应位置,同样的包名称就重合
所以也就相当于我们写了一遍对应代码,即我们导入后,就可以使用对应信息的,只是不会显示对应类给我们看而已
这时java读取jar包的方式
<?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" >
< context: property-placeholder location = " classpath:jdbc.properties" />
< bean id = " dataSource" class = " com.alibaba.druid.pool.DruidDataSource" >
< property name = " driverClassName" value = " ${jdbc.driver}" />
< property name = " url" value = " ${jdbc.url}" />
< property name = " username" value = " ${jdbc.username}" />
< property name = " password" value = " ${jdbc.password}" />
</ bean>
< bean id = " sqlSessionFactory" class = " org.mybatis.spring.SqlSessionFactoryBean" >
< property name = " dataSource" ref = " dataSource" />
< property name = " typeAliasesPackage" value = " com.lagou.domain" > </ property>
< property name = " configLocation" value = " classpath:sqlMapConfig.xml" > </ property>
</ bean>
< bean class = " org.mybatis.spring.mapper.MapperScannerConfigurer" >
< property name = " basePackage" value = " com.lagou.dao" />
</ bean>
</ beans>
对应的jdbc.properties文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///spring_db?characterEncoding=utf8&useSSL=false
jdbc.username=root
jdbc.password=123456
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>
< setting name = " mapUnderscoreToCamelCase" value = " true" />
</ settings>
</ configuration>
子工程ssm_service构建:
用来存放Service层的代码,也就是使用数据库代码的业务代码
配置ssm_service工程的pom.xml文件:
< dependencies>
< dependency>
< groupId> com.lagou</ groupId>
< artifactId> ssm_dao</ artifactId>
< version> 1.0-SNAPSHOT</ version>
</ dependency>
</ dependencies>
创建TestService接口和实现类:
package com. lagou. service ;
import com. lagou. domain. Test ;
import java. util. List ;
public interface TestService {
public List < Test > findAllTest ( ) ;
}
package com. lagou. service. impl ;
import com. lagou. dao. TestMapper ;
import com. lagou. domain. Test ;
import com. lagou. service. TestService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Service ;
import java. util. List ;
@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" >
< context: component-scan base-package = " com.lagou.service" >
</ context: component-scan>
< import resource = " classpath:applicationContext-dao.xml" />
</ beans>
子工程ssm_web构建:
用来存放Web层的代码,也就是操作调用业务层代码与前端交互的
配置ssm_web工程的pom.xml文件:
< packaging> war</ packaging>
< dependencies>
< dependency>
< groupId> com.lagou</ groupId>
< artifactId> ssm_service</ artifactId>
< version> 1.0-SNAPSHOT</ version>
</ dependency>
</ dependencies>
创建Controller:
package com. lagou. controller ;
import com. lagou. domain. Test ;
import com. lagou. service. TestService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Controller ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
import java. util. List ;
@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" >
< context: component-scan base-package = " com.lagou.controller" > </ context: component-scan>
< mvc: annotation-driven> </ mvc: annotation-driven>
< 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" >
< import resource = " classpath:applicationContext-service.xml" />
</ beans>
配置web.xml:
<?xml version="1.0" encoding="UTF-8"?>
< web-app xmlns = " http://xmlns.jcp.org/xml/ns/javaee"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version = " 4.0" >
< 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>
< 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:springmvc.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>
< 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>
</ web-app>
上面都初步完成的基础架构创建,接下来开始写真正的代码了
课程管理模块功能分析:
在本次的项目中,首先完成课程管理模块
课程管理模块实现以下功能:
课程需要的操作:
多条件查询
图片上传
新建课程信息
回显课程信息,进行修改
修改课程信息
课程状态管理
课程内容展示,展示章节信息和课时信息,可以通过这些信息实现前端操作回显
回显章节对应的课程信息
章节需要的操作:
新建章节信息
回显章节信息,进行修改,这里前端可以操作
修改章节信息
修改章节状态
课时需要的操作:
新建课时信息
回显课时信息,进行修改,这里前端可以操作
修改课时信息
修改课时状态
课程管理模块表设计:
创建数据库及表:
sql语句地址:
链接:https://pan.baidu.com/s/1nBzKDzF5JJAfBGDaEi2zxg
提取码:alsk
注意:排序的操作,可以通过表来操作
表关系介绍:
ER图:
虽然他们都有对应联系(主从表),但是这个联系是为了确定位置的,但是影响开发效率
但是若我们不不添加这些联系,虽然测试时,不会出错,但可能会有漏网之鱼,即多余数据,对后续维护可能会造成影响
所以我们一般都会有对应索引(也可以加快查询速率,实际上是对表底层查询操作的变化)
数据实体描述 :
在对应sql中有对应描述,看如下图:
字段设置了comment,使得有描述,所以若要知道对应描述,可以去表里面看
课程管理模块的实现:
多条件课程列表查询 :
需求分析 :
根据课程名称及课程状态进行多条件查询:
在这里说明一下,一般的,大的项目都需要对应的接口文档,也就是提供对应规范
如请求地址:请求的地址信息
请求方式:如POST方式
接口描述:是哪个模块的接口,或者进行什么操作的
请求参数:需要传递的参数有哪些,以及对应参数说明
请求示例:请求的例子
响应结果示例:请求后,响应回来的参数例子
一般我们都是按照上面的操作来进行开发,这个一般需要自己公司里提供,这里就不提供了
对应实体类,参照表来编写,具体地址:
链接:https://pan.baidu.com/s/1VhDnglRa1yfiFpFnPNa6dg
提取码:alsk
其中说明一下:
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;
}
}
实体CourseVo类(View Object表现层对象:主要用于表现层来接收参数的),使得多个表的数据都可以放在这里进行统一操作
如添加数据时,对应传递的数据若包含两个及其两个以上的表字段变量,就需要对应一个新的类了,这里是CourseVo类
而使用这个类,存放后,可以使用对应方法,进行赋值:如BeanUtils.copyProperties()方法,需要jar包导入
因为最后操作的还是对应表的实体类,因为这个CourseVo类只是存放了对应需要的字段,而不是全部
接下来说明一下,为什么不直接使用这个类,而是需要对应实体类的存在
根据下面的添加课程及讲师信息的saveCourseOrTeacher方法为例子:
因为就算封装了全部,也没有对应多个表的联系
如外键和主键的对应变量
注意:数据库表不一定是设置了主键和外键(一般都会设置主键),只是有对应变量而已
而设置主键和外键,最主要的就是数据的对应关系操作,使得不会出现多余数据
因为一个类里面基本操作不了,实际上也是可以
如将这个类以本体作为变量,虽然由两个类,变成只有一个类了
但是发现会有多余字段,而且表逻辑性不好
使得效率(运行的效率,效率低,执行速度越慢,这里统称为效率)变低(同样是多个嵌套,但这里初始化变多了)
即虽然使得类变少(空间变少),但执行速度变慢了(少嵌套的情况下)
若不以本体,那么就少创建两个对象,那么多个嵌套也有优势了
若没有进行嵌套的话,那么效率就高点,因为只创建一个对象(赋值时),而他们需要三个对象
即少创建了两个对象,如使用上面的BeanUtils.copyProperties()方法就需要创建对应对象,加起来多创建了两个对象
我们发现,将代码全部放在一起,可以提高执行速度和内存空间(不以本体),当然也节省了硬盘空间,但这个可以忽略不计
内存空间的节省通常也会伴随着硬盘空间的节省,因为我们都是从硬盘的文件到内存的(而不是的通常不会,如数据库)
所以数据库的所占硬盘空间基本不会和内存空间联系,可以看成他们是有联系的
但是,若全部放在一起就不好维护,以及对应关系的确定,因为这样的效率与维护的成本来说太过于渺小
就如我们使用框架提高了开发速度,但不使用,则降低开发速度,也可以说使用is-else虽然比不上for循环判断
但实际上执行时,if-else要快,虽然我代码全部弄在一起,虽然很难维护,但快
所以在空间和内存时间(执行速度)的基础上,还要有维护
不能使得维护起来困难,所以一般在内存空间和时间(执行速度)上的小额度提升时,优先考虑维护性
小额度:就是非常小的提升,大额度提升那么就不考虑对应维护性了,这是相对对应代码的额度提升
若又可以提高维护性,又可以提高内存空间和时间(执行速度),那么我们也肯定是趋向与这一种的
而使用BeanUtils.copyProperties()方法可以然一个类的变量进行利用最大化,而不会产生多余字段,且分工明确
而不是将所有的信息放入一个类里面,这样的耦合度是非常高的(虽然方便)
所有说,在考虑到需要多个表变量时,用一个类来刚好获取
然后对相应的类进行赋值,这样每个变量都进行操作了,而没有多余的
这样以少的代码,实现同样的操作,且代码相对较少,比较好维护
而在开发中,我们也尽量不要将不同的类型变量放在一个类里面,就如一个狗狗接口里面不能有飞行方法等等
否则,当项目足够大时,再次看回来,会发现有很多多余代码,我们且很难再次进行维护
就如我们不会认为狗狗接口里面是会飞一样,所以一个大的接口,需要变成一个一个的小接口
上面的类也是如此,虽然一个类就可以搞定,但维护性不高
我们来个实例:假如一个类里面有10000个变量,我让你去这些变量中
找一个变量是属于用户表的,你一定是每个变量都会对应一下
那么假如有1000个表,不可能都去看一下吧,那么ok假如有注释,那么这些注释你也要一路看下去
万一没看到,略过了,那么需要重新看,这是非常痛苦的,若我们将表名与类名对象(见名知义)
就我们将这些变量从一开始就分工明确,如User类放user表的字段,很明显,我们维护时,直接找到这个类即可
在合并的类存在时(如CourseVo类),若这时你还想要这个类
那么当需要添加一个表字段时,你就需要添加一个实体,并在这个类里面添加对应字段
那么这时你会发现变得麻烦,更加的是,随着项目越来越大,每次创建这个对象,都要很久,影响业务(当然很少的变量下可以)
那么只需要初始化一次了,可是项目一般都是非常多的,所有基本不可能很少,所以不考虑
这就是我们为什么需要实体类的原因,而不是将所有变量放在一起,所以CourseVo类只是用来放多个表数据的,而不是全部变量
使得初始化时浪费时间少
正是由于这样,使得表与sql对应,那么在分开后,这个存放了总体的类一般都是存放数据的,所以可以用来当接收参数
而对于局部的存放全部变量类,一般也不会当成参数
主要的是为了防止其他方法里使用这个方法时,没有创建这个CourseVo类的原因(因为对应关系)
所以我们一般都会创建对应类来当参数
而不是直接用CourseVo类来当参数,虽然可以少创建对象
最后:最重要的原因是,每个表的字段是可能相同的,以及使用方法时,通过方法名和参数,就可以知道是干什么的了
所有通常不会放在一起
我们发现
无论是空间(空间在这里一般称为内存空间,因为硬盘空间可以忽略,因为程序还不足以影响硬盘空间)时间(执行速度)
都是进行互相影响的
所以我们需要算法来使得更少的代码来实现同样的效果,以后再说算法,实际上VO只是针对某些需求需要的,如果前端移动数据,那么可以放在一起,虽然一次查询很多,但是后续不用查询了,各有好处吧
注意:这个类主要存放的是多个表的字段变量,而一些像状态管理的,表自己就可以操作的,就不需要了
虽然也可以写上,但是不好维护
这个类需要自己根据需求来编写:
package com. lagou. domain ;
public class CourseVO {
private String courseName;
private Integer status;
public String getCourseName ( ) {
return courseName;
}
public void setCourseName ( String courseName) {
this . courseName = courseName;
}
public Integer getStatus ( ) {
return status;
}
public void setStatus ( Integer status) {
this . status = status;
}
}
Dao层:CourseMapper:
package com. lagou. dao ;
import com. lagou. domain. Course ;
import java. util. List ;
public interface CourseMapper {
public List < Course > findCourseByCondition ( Course course) ;
}
对应映射配置文件(CourseMapper.xml):
<?xml version="1.0" encoding="UTF-8" ?>
<! DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
< mapper namespace = " com.lagou.dao.CourseMapper" >
< select id = " findCourseByCondition" parameterType = " com.lagou.domain.CourseVo"
resultType = " com.lagou.domain.Course" >
select * from course
< where>
< if test = " courseName !=null and courseName!=''" >
and course_name like '%${courseName}%'
</ if>
< if test = " status !=null and status!=''" >
and status = #{status}
</ if>
< if test = " true" >
and is_Del != 1
</ if>
</ where>
</ select>
</ mapper>
Service层:CourseService及其实现类 :
package com. lagou. service ;
import com. lagou. domain. Course ;
import com. lagou. domain. CourseVo ;
import java. util. List ;
public interface CourseService {
public List < Course > findCourseByCondition ( CourseVo courseVo) ;
}
package com. lagou. service. impl ;
import com. lagou. dao. CourseMapper ;
import com. lagou. domain. Course ;
import com. lagou. domain. CourseVo ;
import com. lagou. service. CourseService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Service ;
import java. util. List ;
@Service
public class CourseServiceImpl implements CourseService {
@Autowired
private CourseMapper courseMapper;
@Override
public List < Course > findCourseByCondition ( CourseVo courseVo) {
List < Course > courseByCondition = courseMapper. findCourseByCondition ( courseVo) ;
return courseByCondition;
}
}
Web层:CourseController :
package com. lagou. controller ;
import com. lagou. domain. Course ;
import com. lagou. domain. CourseVo ;
import com. lagou. domain. ResponseResult ;
import com. lagou. service. CourseService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. web. bind. annotation. RequestBody ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
import java. util. List ;
@RestController
@RequestMapping ( "/course" )
public class CourseController {
@Autowired
private CourseService courseService;
@RequestMapping ( "/findCourseByCondition" )
public ResponseResult findCourseByCondition ( @RequestBody CourseVo courseVo) {
List < Course > courseByCondition = courseService. findCourseByCondition ( courseVo) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "响应成功" , courseByCondition) ;
return responseResult;
}
}
添加日志文件log4j.properties:
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout
对应jar包:
< dependency>
< groupId> org.slf4j</ groupId>
< artifactId> slf4j-log4j12</ artifactId>
< version> 1.7.7</ version>
</ dependency>
< dependency>
< groupId> log4j</ groupId>
< artifactId> log4j</ artifactId>
< version> 1.2.17</ version>
</ dependency>
对应日志文件的介绍在63章博客里有
接下来就可以启动服务器,使用Postman测试接口了,测试(使用)方式56章博客里有
注意:对应sql表来说,手动设置排序的会优先于主键的排序,这个多用于排序字段
课程图片上传 :
在没有使用框架的项目中是没有进行图片的回显的(并不需要立即回显)
那么对应的得到图片信息(如在服务器的地址)会与web层进行一起操作,即顺便存到数据库
而这里由于需要立即回显,那么我们就将对应得到的图片信息(如在服务器的地址)与web层分开了
使得分开操作,如点击上传按钮,使得可以回显,然后存放到数据库里面,但是若多次上传图片
而不保存图片信息到数据库,那么对应的图片在服务器路径会多出很多,这是一个问题,后续看需求解决
上面的实际上也可以是其他的文件,反正是文件的上传(如音视频等等),因为是字节流的输入和输出
但要注意不要超过自己设置的配置文件的对应文件的最大大小,否则报错
需求分析:
需求:在新增课程页面需要进行图片上传,并回显图片信息:
添加部分springmvc.xml:
< 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) throws IOException {
if ( file. isEmpty ( ) ) {
throw new RuntimeException ( ) ;
}
String realPath = request. getServletContext ( ) . getRealPath ( "/" ) ;
String substring = realPath. substring ( 0 , realPath. indexOf ( "ssm_web" ) ) ;
String originalFilename = file. getOriginalFilename ( ) ;
String newFileName = System . currentTimeMillis ( ) +
originalFilename. substring ( originalFilename. lastIndexOf ( "." ) ) ;
String uploadPath = substring + "upload\\" ;
File file1 = new File ( uploadPath, newFileName) ;
if ( ! file1. getParentFile ( ) . exists ( ) ) {
file1. getParentFile ( ) . mkdirs ( ) ;
System . out. println ( "创建目录" + file1) ;
}
file. transferTo ( file1) ;
HashMap < String , String > objectObjectHashMap = new HashMap < > ( ) ;
objectObjectHashMap. put ( "fileName" , newFileName) ;
objectObjectHashMap. put ( "filePath" , "http://localhost:8080/upload/" + newFileName) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "图片上传成功" ,
objectObjectHashMap) ;
return responseResult;
}
}
使用Postman测试接口
新建课程信息 :
需求分析:
填写好新增课程信息后,点击保存,将表单信息保存到数据库中
Dao层:添加部分CourseMapper :
public void saveCourse ( Course course) ;
public void saveTeacher ( Teacher teacher) ;
添加部分CourseMapper.xml:
< insert id = " saveCourse" parameterType = " Course" >
INSERT INTO course(
course_name,
brief,
preview_first_field,
preview_second_field,
course_img_url,
course_list_img,
sort_num,
price,
discounts,
sales,
discounts_tag,course_description_mark_down,
create_time,
update_time
) VALUES(#{courseName},#{brief},#{previewFirstField},#{previewSecondField},#
{courseImgUrl},
#{courseListImg},#{sortNum},#{price},#{discounts},#{sales},#{discountsTag},#
{courseDescriptionMarkDown},
#{createTime},#{updateTime});
< selectKey resultType = " int" order = " AFTER" keyProperty = " id" >
select last_insert_id()
</ selectKey>
</ insert>
< insert id = " saveTeacher" parameterType = " Teacher" >
INSERT INTO teacher(course_id,
teacher_name,
position,
description,
create_time,
update_time)
VALUES (#{courseId}, #{teacherName}, #{position}, #{description}, #{createTime}, #
{updateTime});
</ insert>
注意:由于参数过多,前面的CourseVo的变量太少,不足以满足我们需求,所以我们需要添加变量:
package com. lagou. domain ;
import java. util. Date ;
public class CourseVo {
private int id;
private String courseName;
private String brief;
private double price;
private String priceTag;
private double discounts;
private String discountsTag;
private String courseDescriptionMarkDown;
private String courseDescription;
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;
private int status;
private int sortNum;
private String previewFirstField;
private String previewSecondField;
private int sales;
private String teacherName;
private String position;
private String description;
public int getId ( ) {
return id;
}
public void setId ( int id) {
this . id = id;
}
public String getCourseName ( ) {
return courseName;
}
public void setCourseName ( String courseName) {
this . courseName = courseName;
}
public String getBrief ( ) {
return brief;
}
public void setBrief ( String brief) {
this . brief = brief;
}
public double getPrice ( ) {
return price;
}
public void setPrice ( double price) {
this . price = price;
}
public String getPriceTag ( ) {
return priceTag;
}
public void setPriceTag ( String priceTag) {
this . priceTag = priceTag;
}
public double getDiscounts ( ) {
return discounts;
}
public void setDiscounts ( double discounts) {
this . discounts = discounts;
}
public String getDiscountsTag ( ) {
return discountsTag;
}
public void setDiscountsTag ( String discountsTag) {
this . discountsTag = discountsTag;
}
public String getCourseDescriptionMarkDown ( ) {
return courseDescriptionMarkDown;
}
public void setCourseDescriptionMarkDown ( String courseDescriptionMarkDown) {
this . courseDescriptionMarkDown = courseDescriptionMarkDown;
}
public String getCourseDescription ( ) {
return courseDescription;
}
public void setCourseDescription ( String courseDescription) {
this . courseDescription = courseDescription;
}
public String getCourseImgUrl ( ) {
return courseImgUrl;
}
public void setCourseImgUrl ( String courseImgUrl) {
this . courseImgUrl = courseImgUrl;
}
public int getIsNew ( ) {
return isNew;
}
public void setIsNew ( int isNew) {
this . isNew = isNew;
}
public String getIsNewDes ( ) {
return isNewDes;
}
public void setIsNewDes ( String isNewDes) {
this . isNewDes = isNewDes;
}
public int getLastOperatorId ( ) {
return lastOperatorId;
}
public void setLastOperatorId ( int lastOperatorId) {
this . lastOperatorId = lastOperatorId;
}
public Date getAutoOnlineTime ( ) {
return autoOnlineTime;
}
public void setAutoOnlineTime ( Date autoOnlineTime) {
this . autoOnlineTime = autoOnlineTime;
}
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 int getIsDel ( ) {
return isDel;
}
public void setIsDel ( int isDel) {
this . isDel = isDel;
}
public int getTotalDuration ( ) {
return totalDuration;
}
public void setTotalDuration ( int totalDuration) {
this . totalDuration = totalDuration;
}
public String getCourseListImg ( ) {
return courseListImg;
}
public void setCourseListImg ( String courseListImg) {
this . courseListImg = courseListImg;
}
public int getStatus ( ) {
return status;
}
public void setStatus ( int status) {
this . status = status;
}
public int getSortNum ( ) {
return sortNum;
}
public void setSortNum ( int sortNum) {
this . sortNum = sortNum;
}
public String getPreviewFirstField ( ) {
return previewFirstField;
}
public void setPreviewFirstField ( String previewFirstField) {
this . previewFirstField = previewFirstField;
}
public String getPreviewSecondField ( ) {
return previewSecondField;
}
public void setPreviewSecondField ( String previewSecondField) {
this . previewSecondField = previewSecondField;
}
public int getSales ( ) {
return sales;
}
public void setSales ( int sales) {
this . sales = sales;
}
public String getTeacherName ( ) {
return teacherName;
}
public void setTeacherName ( String teacherName) {
this . teacherName = teacherName;
}
public String getPosition ( ) {
return position;
}
public void setPosition ( String position) {
this . position = position;
}
public String getDescription ( ) {
return description;
}
public void setDescription ( String description) {
this . description = description;
}
}
Service层:添加部分CourseService 及其实现类:
public void saveCourseOrTeacher ( CourseVo courseVo) throws InvocationTargetException ,
IllegalAccessException ;
@Override
public void saveCourseOrTeacher ( CourseVo courseVo) throws InvocationTargetException ,
IllegalAccessException {
Course course = new Course ( ) ;
BeanUtils . copyProperties ( course, courseVo) ;
Date date = new Date ( ) ;
course. setCreateTime ( date) ;
course. setUpdateTime ( date) ;
courseMapper. saveCourse ( course) ;
int id = course. getId ( ) ;
Teacher teacher = new Teacher ( ) ;
BeanUtils . copyProperties ( teacher, courseVo) ;
teacher. setCreateTime ( date) ;
teacher. setUpdateTime ( date) ;
teacher. setIsDel ( 0 ) ;
teacher. setCourseId ( id) ;
courseMapper. saveTeacher ( teacher) ;
}
Web层:添加部分CourseController:
@RequestMapping ( "saveOrUpdateCourse" )
public ResponseResult saveOrUpdateCourse ( @RequestBody CourseVo courseVo) throws
InvocationTargetException , IllegalAccessException {
courseService. saveCourseOrTeacher ( courseVo) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "响应成功" , null ) ;
return responseResult;
}
注意:由于BeanUtils.copyProperties(course, courseVo)方法不能使得null赋值给Date
所以我们删掉CourseVo对应类型的Date的变量及其对应的set和get方法
使用Postman测试接口(若没有删掉对应变量,则会报错,记得删掉后进行测试)
修改课程信息 :
点击保存按钮,将修改后的课程信息保存到数据库中
首先我们先得到对应数据来进行回显操作:
主要是sql的编写:
SELECT
c. * ,
t. teacher_name,
t. position,
t. description
FROM
course c
LEFT JOIN teacher t
ON c. id = t. id
WHERE c. id = 16
Dao层:添加部分CourseMapper:
public CourseVo findCourseById ( Integer id) ;
添加部分CourseMapper.xml:
< select id = " findCourseById" parameterType = " int" resultType = " CourseVo" >
SELECT c.*,
t.teacher_name,
t.position,
t.description
FROM course c
LEFT JOIN teacher t
ON c.id = t.id
WHERE c.id = #{id}
</ select>
Service层:添加部分CourseService及其实现类:
public CourseVo findCourseById ( Integer id) ;
@Override
public CourseVo findCourseById ( Integer id) {
CourseVo courseById = courseMapper. findCourseById ( id) ;
return courseById;
}
Web层:添加部分CourseController:
@RequestMapping ( "/findCourseById" )
public ResponseResult findCourseById ( Integer integer) {
CourseVo courseById = courseService. findCourseById ( integer) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "根据id查询课程信息成
功", courseById) ;
return responseResult;
}
使用Postman测试接口(自己处理,后面会提示一下)
回显后,接下来我们进行课程的修改操作,在这里提醒一下:在表单中,对应输入框只要输入了数据,那么就不是空串,如空格
当然sql里的表,只要没有设置默认值,那么基本第一次添加时,没添加的地方默认是null
若设置了默认值,那么就是设置的默认值,如0等等
而由于后台操作数据时,若是根据名称来获得,对应名称不在,结果一般是null,不写,结果一般是""(空串)
而使用json解析时,对应key不在,一般不会解析赋值,即使用默认的
若是是"“,非String使用默认(包括整型默认值和null)和String使用”"(空串),整型默认值包括0,0.0或者其他
我们发现结果有整型默认值或者null或者""的,而由于整型默认值的存在
所以有时候网站上出现的默认0,0.0或者其他的情况,一般都是0,但上面的操作若在判断解决后
一般别人是通过不了开发者工具来使得数据库进行不合理的数据存放的,因为无非就是如下情况
前台有参数:后台显示值是空值或者有值,前台无参数:后台显示值是默认值(整型默认值,null)等等
至于整型默认值,我们可以不做要求,因为反正都是合理的(除非后台不合理,或者报错,那这是后台的问题)
而出现的null和"",所以下面的sql语句中都对这两种情况进行操作了
所以数据库里面一般不会使得出现null和空值(除非没有添加),而出现这些情况,我们一般是不会进行操作字段的,如修改等等
所以可以说明:在没有后台错误的情况,开发者工具一般不可能使得数据库数据出问题
就算没有设置判断,为null或者""也只是数据的不合理而已(判断基本是防止全部删除的)
需求分析:
Dao层:添加部分CourseMapper:
public void updateCourse ( Course course) ;
public void updateTeacher ( Teacher teacher) ;
添加部分CourseMapper.xml:
< update id = " updateCourse" parameterType = " Course" >
update course
< trim prefix = " SET" suffixOverrides = " ," >
< if test = " courseName != null and courseName != ''" >
course_name = #{courseName},
</ if>
< if test = " brief != null and brief != ''" >
brief=#{brief},
</ if>
< if test = " previewFirstField != null and previewFirstField != ''" >
preview_first_field=#{previewFirstField},
</ if>
< if test = " previewSecondField != null and previewSecondField != ''" >
preview_second_field=#{previewSecondField},
</ if>
< if test = " courseImgUrl != null and courseImgUrl != ''" >
course_img_url=#{courseImgUrl},
</ if>
< if test = " courseListImg != null and courseListImg != ''" >
course_list_img=#{courseListImg},
</ if>
< if test = " sortNum != null and sortNum != ''" >
sort_num=#{sortNum},
</ if>
< if test = " price != null and price != ''" >
price=#{price},
</ if>
< if test = " discounts != null and discounts != ''" >
discounts=#{discounts},
</ if>
< if test = " sales != null and sales != '' or sales==0" >
sales=#{sales},
</ if>
< if test = " discountsTag != null and discountsTag != ''" >
discounts_tag=#{discountsTag},
</ if>
< if test = " courseDescriptionMarkDown != null and
courseDescriptionMarkDown != ''" >
course_description_mark_down=#{courseDescriptionMarkDown},
</ if>
< if test = " updateTime != null" >
update_time=#{updateTime},
</ if>
</ trim>
< where>
< if test = " id!=null and id != '' " > id=#{id}</ if>
</ where>
</ update>
< update id = " updateTeacher" parameterType = " Teacher" >
update teacher
< trim prefix = " SET" suffixOverrides = " ," >
< if test = " teacherName != null and teacherName != ''" >
teacher_name = #{teacherName},
</ if>
< if test = " position != null and position != ''" >
position = #{position},
</ if>
< if test = " description != null and description != ''" >
description = #{description},
</ if>
< if test = " updateTime != null" >
update_time=#{updateTime}
</ if>
</ trim>
< where>
< if test = " courseId != null and courseId != '' " > course_id = #{courseId}</ if>
</ where>
</ update>
Service层:添加部分CourseService及其实现类:
public void updateCourseOrTeacher ( CourseVo courseVo) throws InvocationTargetException ,
IllegalAccessException ;
@Override
public void updateCourseOrTeacher ( CourseVo courseVo) throws InvocationTargetException ,
IllegalAccessException {
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) ;
}
Web层:修改部分CourseController(扩展saveOrUpdateCourse方法):
@RequestMapping ( "saveOrUpdateCourse" )
public ResponseResult saveOrUpdateCourse ( @RequestBody CourseVo courseVo) throws
InvocationTargetException , IllegalAccessException {
ResponseResult responseResult;
if ( courseVo. getId ( ) != 0 ) {
courseService. saveCourseOrTeacher ( courseVo) ;
responseResult = new ResponseResult ( true , 200 , "新增成功" , null ) ;
} else {
courseService. updateCourseOrTeacher ( courseVo) ;
responseResult = new ResponseResult ( true , 200 , "修改成功" , null ) ;
}
return responseResult;
}
使用Postman测试接口
课程状态管理:
需求分析:
在课程列表展示页面中,可以通过点击 上架/下架按钮,修改课程状态:
Dao层:添加部分CourseMapper:
public void updateCourseStatus ( Course course) ;
添加部分CourseMapper.xml:
< update id = " updateCourseStatus" parameterType = " 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) {
Course course = new Course ( ) ;
course. setId ( id) ;
course. setStatus ( status) ;
course. setUpdateTime ( new Date ( ) ) ;
courseMapper. updateCourseStatus ( course) ;
}
Web层:添加部分CourseController:
@RequestMapping ( "/updateCourseStatus" )
public ResponseResult updateCourseStatus ( Integer id , Integer status) {
courseService. updateCourseStatus ( id, status) ;
HashMap < String , Object > objectObjectHashMap = new HashMap < > ( ) ;
objectObjectHashMap. put ( "status" , status) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "课程状态变更成功" ,
objectObjectHashMap) ;
return responseResult;
}
使用Postman测试接口
课程内容展示:
需求分析:
需求:点击内容管理,展示课程对应的课程内容(课程内容包含了章节和课时,还有回显的课程信息)
现在我们编写查询章节和课时信息的代码:
Dao层:CourseContentMapper:
package com. lagou. dao ;
import com. lagou. domain. CourseSection ;
import java. util. List ;
public interface CourseContentMapper {
public List < CourseSection > findSectionAndLessonByCourseId ( Integer courseId) ;
}
对应映射配置文件(CourseContentMapper.xml):
<?xml version="1.0" encoding="UTF-8" ?>
<! DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
< mapper namespace = " com.lagou.dao.CourseContentMapper" >
< resultMap id = " SectionAndLessonResultMap" type = " CourseSection" >
< id property = " id" column = " id" />
< result property = " courseId" column = " course_id" />
< result property = " sectionName" column = " section_name" />
< result property = " description" column = " description" />
< result property = " createTime" column = " create_time" />
< result property = " updateTime" column = " update_time" />
< result property = " isDe" column = " is_del" />
< result property = " orderNum" column = " order_num" />
< result property = " status" column = " status" />
< collection property = " lessonList" ofType = " CourseLesson" >
< id property = " id" column = " lessonId" />
< result property = " courseId" column = " course_id" />
< result property = " sectionId" column = " section_id" />
< result property = " theme" column = " theme" />
< result property = " duration" column = " duration" />
< result property = " isFree" column = " is_free" />
< result property = " orderNum" column = " order_numl" />
< result property = " status" column = " statusl" />
</ collection>
</ resultMap>
< select id = " findSectionAndLessonByCourseId" resultMap = " SectionAndLessonResultMap" >
SELECT
cs.*,
cl.id lessonid,
cl.course_id,
cl.section_id,
cl.theme,
cl.duration,
cl.create_time,
cl.update_time,
cl.is_del,
cl.order_num order_numl,
cl.status statusl
FROM
course_section cs
LEFT JOIN course_lesson cl
ON cs.id = cl.section_id
WHERE cs.course_id = #{id}
ORDER BY cs.order_num
</ select>
</ mapper>
Service层:CourseContentService及其实现类 :
package com. lagou. service ;
import com. lagou. domain. CourseSection ;
import java. util. List ;
public interface CourseContentService {
public List < CourseSection > findSectionAndLessonByCourseId ( Integer courseId) ;
}
package com. lagou. service. impl ;
import com. lagou. dao. CourseContentMapper ;
import com. lagou. domain. CourseSection ;
import com. lagou. service. CourseContentService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. stereotype. Service ;
import java. util. List ;
@Service
public class CourseContentServiceImpl implements CourseContentService {
@Autowired
private CourseContentMapper courseContentMapper;
@Override
public List < CourseSection > findSectionAndLessonByCourseId ( Integer courseId) {
List < CourseSection > sectionAndLessonByCourseId =
courseContentMapper. findSectionAndLessonByCourseId ( courseId) ;
return sectionAndLessonByCourseId;
}
}
Web层:CourseContentController:
package com. lagou. controller ;
import com. lagou. domain. CourseSection ;
import com. lagou. domain. ResponseResult ;
import com. lagou. service. CourseContentService ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. web. bind. annotation. RequestMapping ;
import org. springframework. web. bind. annotation. RestController ;
import java. util. List ;
@RestController
@RequestMapping ( "/courseContent" )
public class CourseContentController {
@Autowired
private CourseContentService courseContentService;
@RequestMapping ( "/findSectionAndLesson" )
public ResponseResult findSectionAndLessonByCourseId ( Integer courseId) {
List < CourseSection > sectionAndLessonByCourseId =
courseContentService. findSectionAndLessonByCourseId ( courseId) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "章节及课时内容查询成功" ,
sectionAndLessonByCourseId) ;
return responseResult;
}
}
使用Postman测试接口
上面只是查询对应课程内容(章节和课时信息),但前端通常有对应课程信息,即现在我们进行回显操作
Dao层:添加部分CourseContentMapper:
public Course findCourseByCourseId ( Integer courseId) ;
添加部分CourseContentMapper.xml:
< select id = " findCourseByCourseId" parameterType = " int" resultType = " Course" >
select id, course_name
from course
where id = #{id}
</ select>
Service层:添加部分CourseContentService及其实现类 :
public Course findCourseByCourseId ( Integer courseId) ;
@Override
public Course findCourseByCourseId ( Integer courseId) {
Course courseByCourseId = courseContentMapper. findCourseByCourseId ( courseId) ;
return courseByCourseId;
}
Web层:添加部分CourseContentController:
@RequestMapping ( "/findCourseByCourseId" )
public ResponseResult findCourseByCourseId ( Integer courseId) {
Course courseByCourseId = courseContentService. findCourseByCourseId ( courseId) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "查询课程信息成功" ,
courseByCourseId) ;
return responseResult;
}
使用Postman测试接口
新建章节信息
需求分析:
在课程内容展示页面中,可以通过点击添加阶段按钮,添加章节信息
Dao层:添加部分CourseContentMapper:
public void saveSection ( CourseSection courseSection) ;
添加部分CourseContentMapper.xml:
< insert id = " saveSection" parameterType = " 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 courseSection) ;
@Override
public void saveSection ( CourseSection courseSection) {
Date date = new Date ( ) ;
courseSection. setCreateTime ( date) ;
courseSection. setUpdateTime ( date) ;
courseContentMapper. saveSection ( courseSection) ;
}
Web层:添加部分CourseContentController:
@RequestMapping ( "/saveOrUpdateSection" )
public ResponseResult saveOrUpdateSection ( @RequestBody CourseSection courseSection) {
courseContentService. saveSection ( courseSection) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "新增章节成功" , null ) ;
return responseResult;
}
使用Postman测试接口
修改章节信息
需求分析:
点击确定按钮,将修改后的章节信息保存到数据库中
注意:这里就不需要回显了,具体原因如下:
我们在修改课程时,是需要回显的,因为我们并没有在同一个页面,也就是没有具体的数据
而这个章节,由于是在同一个页面,即我们在查询章节信息和课程信息中是有对应数据的
所以前端是可以帮我们进行对应的回显
那么你可能会有疑惑:为什么我们不通过后台得到数据进行回显呢,那是因为若我们需要后台得到数据回显
那么也就必须好编写对应代码,造成执行速度变低(前端的逻辑操作数据,通常比后端的操作数据快,特别是远程时,更加明显)
而我们在查询到章节信息和课时信息时,这些信息我们都放在前端的
所以我们可以通过前端来直接获得,这样节省很多代码以及提高执行速度(或者说执行效率)
最后:回显实际上基本都是根据id查询对应的信息的操作,然后将对应数据显示在页面上进行展示的,通常用于修改
所以一般的,在修改操作之前,都需要回显后,再进行修改操作
Dao层:添加部分CourseContentMapper:
public void updateSection ( CourseSection courseSection) ;
添加部分CourseContentMapper.xml:
< update id = " updateSection" parameterType = " CourseSection" >
UPDATE course_section
< trim prefix = " SET" suffixOverrides = " ," >
< if test = " sectionName != null and sectionName != ''" >
section_name = #{sectionName},
</ if>
< if test = " description != null and description != ''" >
description = #{description},
</ if>
< if test = " orderNum != null and orderNum != '' or orderNum == 0" >
order_num = #{orderNum},
</ if>
< if test = " updateTime != null" >
update_time=#{updateTime}
</ if>
</ trim>
< where>
< if test = " id != null and id != '' " > id = #{id}</ if>
</ where>
</ update>
Service层:添加部分CourseContentService及其实现类 :
public void updateSection ( CourseSection courseSection) ;
@Override
public void updateSection ( CourseSection courseSection) {
courseSection. setUpdateTime ( new Date ( ) ) ;
courseContentMapper. updateSection ( courseSection) ;
}
Web层:修改部分CourseContentController(扩展saveOrUpdateSection方法):
@RequestMapping ( "/saveOrUpdateSection" )
public ResponseResult saveOrUpdateSection ( @RequestBody CourseSection courseSection) {
ResponseResult responseResult
if ( courseSection. getId ( ) == null ) {
courseContentService. saveSection ( courseSection) ;
responseResult = new ResponseResult ( true , 200 , "新增章节成功" , null ) ;
} else {
courseContentService. updateSection ( courseSection) ;
responseResult = new ResponseResult ( true , 200 , "修改章节成功" , null ) ;
}
return responseResult;
}
使用Postman测试接口
这里说明一下为什么新增操作和修改操作要放到一起:
第一:对应传递的参数基本一致,除了对应id
第二:修改操作的页面和新增操作的页面基本是同一个(在少数情况下,如果新增和修改的业务代码基本不会相同,那么建议分开)
只是对应传递的参数id的不同(一般是这个,传递空串),或者没有加上id
若你不放在一起,那么对应的Controller要多写一个,且前端也要多写一个请求页面
那么我们为什么不简便一点呢,所以一般都放在一起,正是因为只有id的不同,才好进行判断
若你将所有的操作放在一个Controller里,那么基本是很难判断出来的,不像这个只需要判断id
比如说回显操作,一般我们只需要传递id,若放在新增操作里,就要将id用json来操作,那么对应的类只有id有值
那么当你新增时,这时虽然我们可以判断id,而进行回显的操作,但是id的判断是肯定只有一次的
若有id一样,那么你肯定也会判断其他字段,这时代码就多起来了
也就出现了前面说的,我们需要维护性,虽然可以简便,但维护性不高
而保存和修改的相似性太高
主要是前端页面相似或者完全相同,导致使用新增和修改一起的,否则基本就要创建提交的按钮(因为不是同一个Controller)
且基本只有id的变化(其他的基本上有多个默认值,如回显)
也更加的省略了修改的操作
其他的省略是没必要的,如回显id,可能其他地方也会用到他的方法,这是主要的,所以基本不会放一起
而修改基本只会在这一个地方,这也是可以放一起的原因
那么我们通常就会优先于在保存里使用修改,而不是回显或者其他操作,这样也就提高空间和时间(执行速度)
而正是因为操作了修改的判断id,其他的判断是非常困难的,所以基本不会放在一起,使得不好维护
实际上我们可以进行比较:
使用回显放在一起:少一个Controller,前端页面多个提交按钮(来时得到id,同一个参数,包含id存放)
使用修改放一起:少一个Controller,原按钮提交(来时得到id,同一个参数,包含id存放)
这时最小的回显操作,也是没有优势的
所以说主要是前端页面相似或者完全相同,导致使用新增和修改一起的
否则基本就要创建提交的按钮(因为不是同一个Controller),而使用修改和添加一起时的回显在前端只是修改名称
修改章节状态
需求分析:
需求:点击修改章节状态按钮,将当前章节信息的状态进行修改
Dao层:添加部分CourseContentMapper:
public void updateSectionStatus ( CourseSection courseSection) ;
添加部分CourseContentMapper.xml:
< update id = " updateSectionStatus" parameterType = " 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 courseSection = new CourseSection ( ) ;
courseSection. setId ( id) ;
courseSection. setStatus ( status) ;
courseSection. setUpdateTime ( new Date ( ) ) ;
courseContentMapper. updateSectionStatus ( courseSection) ;
}
Web层:添加部分CourseContentController:
@RequestMapping ( "/updateSectionStatus" )
public ResponseResult updateSectionStatus ( int id, int status) {
courseContentService. updateSectionStatus ( id, status) ;
Map < String , Object > objectObjectHashMap = new HashMap < > ( ) ;
objectObjectHashMap. put ( "status" , status) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "修改章节状态成功" ,
objectObjectHashMap) ;
return responseResult;
}
使用Postman测试接口
新建课时信息
通过上面的代码编写,若可以的话,可以不看后面的代码,自己进行一次新建课时信息的编写
需求分析:
需求:点击添加课时按钮,将弹出页面填写的课时信息保存到数据库中
Dao层:添加部分CourseContentMapper:
public void saveLesson ( CourseLesson courseLesson) ;
添加部分CourseContentMapper.xml:
< insert id = " saveLesson" parameterType = " CourseLesson" >
INSERT INTO course_lesson (
course_id,
section_id,
theme,
duration,
is_free,
order_num,
create_time,
update_time
)VALUES(#{courseId},#{sectionId},#{theme},#{duration},#{isFree},
#{orderNum},#{createTime},#{updateTime});
</ insert>
Service层:添加部分CourseContentService及其实现类 :
public void saveLesson ( CourseLesson courseLesson) ;
@Override
public void saveLesson ( CourseLesson courseLesson) {
Date date = new Date ( ) ;
courseLesson. setCreateTime ( date) ;
courseLesson. setUpdateTime ( date) ;
courseContentMapper. saveLesson ( courseLesson) ;
}
Web层:添加部分CourseContentController:
@RequestMapping ( "/saveOrUpdateLesson" )
public ResponseResult saveOrUpdateLesson ( @RequestBody CourseLesson courseLesson) {
courseContentService. saveLesson ( courseLesson) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "添加课时成功" , null ) ;
return responseResult;
}
使用使用Postman测试接口
修改课时信息
需求分析:
点击确定按钮,将修改后的课时信息保存到数据库中(回显是前端操作的)
Dao层:添加部分CourseContentMapper:
public void updateLesson ( CourseLesson courseLesson) ;
添加部分CourseContentMapper.xml:
< update id = " updateLesson" parameterType = " CourseLesson" >
UPDATE course_lesson
< trim prefix = " SET" suffixOverrides = " ," >
< if test = " theme != null and theme != ''" >
theme = #{theme},
</ if>
< if test = " duration != null and duration != ''" >
duration = #{duration},
</ if>
< if test = " isFree != null and isFree != ''" >
is_free = #{isFree},
</ if>
< if test = " orderNum != null and orderNum != '' or orderNum == 0" >
order_num = #{orderNum},
</ if>
< if test = " updateTime != null" >
update_time=#{updateTime}
</ if>
</ trim>
< where>
< if test = " id != null and id != '' " > id = #{id}</ if>
</ where>
</ update>
Service层:添加部分CourseContentService及其实现类 :
public void updateLesson ( CourseLesson courseLesson) ;
@Override
public void updateLesson ( CourseLesson courseLesson) {
courseLesson. setUpdateTime ( new Date ( ) ) ;
courseContentMapper. updateLesson ( courseLesson) ;
}
Web层:修改部分CourseContentController(扩展saveOrUpdateLesson方法):
@RequestMapping ( "/saveOrUpdateLesson" )
public ResponseResult saveOrUpdateLesson ( @RequestBody CourseLesson courseLesson) {
ResponseResult responseResult;
if ( courseLesson. getId ( ) == null ) {
courseContentService. saveLesson ( courseLesson) ;
responseResult = new ResponseResult ( true , 200 , "添加课时成功" , null ) ;
} else {
courseContentService. updateLesson ( courseLesson) ;
responseResult = new ResponseResult ( true , 200 , "修改课时成功" , null ) ;
}
return responseResult;
}
使用使用Postman测试接口
到这里可以知道,前端传递的参数只是影响对应参数变量,最终的还是要看sql怎么编写的
如你传递100个参数,而sql没有使用对应的占位符操作或者替换操作,就是单纯的sql语句,如select * from 表名
那么这100个参数也就没有起作用了
修改课时状态:
需求分析:
需求:点击修改课时状态按钮,将当前课时信息的状态进行修改
Dao层:添加部分CourseContentMapper:
public void updateLessonStatus ( CourseLesson courseLesson) ;
添加部分CourseContentMapper.xml:
< update id = " updateLessonStatus" parameterType = " CourseLesson" >
UPDATE course_lesson set
status = #{status},
update_time = #{updateTime}
WHERE id = #{id}
</ update>
Service层:添加部分CourseContentService及其实现类 :
public void updateLessonStatus ( CourseLesson courseLesson) ;
@Override
public void updateLessonStatus ( CourseLesson courseLesson) {
courseLesson. setUpdateTime ( new Date ( ) ) ;
courseContentMapper. updateLessonStatus ( courseLesson) ;
}
Web层:添加部分CourseContentController:
@RequestMapping ( "/updateLessonStatus" )
public ResponseResult updateLessonStatus ( @RequestBody CourseLesson courseLesson) {
courseContentService. updateLessonStatus ( courseLesson) ;
ResponseResult responseResult = new ResponseResult ( true , 200 , "修改课时状态成功" , null ) ;
return responseResult;
}
使用使用Postman测试接口