富文本编辑器wangEditor使用入门
说明:
(1) 为什么要介绍wangEditor?:在【项目演示】中,我们演示了书评网;其中,就包括后台管理系统;而后台管理系统,最重要的就是图书资料的管理;然后,在图书资料管理时,如何对图书信息进行有效的图文编辑是重点;为此,引入了一个JavaScript组件:富文本编辑器wangEditor;
(2)声明: 本篇博客仅仅介绍了wangEditor的最基本使用;不涉及任何与项目业务相关的内容;
一:wangEditor官网简介;
wangEditor组件是国产的,所以阅读起来,没有语言障碍;
二:wangEditor最基本使用:演示;
1.把wangEditor的js文件,添加进项目;
2.前置说明:创建test.ftl和TestController;
我们创建了test.ftl,我们就在test.ftl中编写wangEditor;然后,又创建了TestController;这样以后,当我们启动项目后,通过访问【localhost/test/t1】的时候,就能访问到test.ftl,看到wangEditor的效果了;
3.在test.ftl中编写wangEditor:包括【wangEditor初始化】,【如何读取内容】,【如何写入内容】;(重点,核心!)
test.ftl:
说明:
(1) 在当前前端文件中,引入wangEditor的js文件;
(2) wangEditor初始化:
这样有以后,就能在页面上显示出wangEditor富文本编辑器了;但是,此时wangEditor只是富文本编辑工具;为了能够让wangEditor在项目中实用,我们需要【读取wangEditor的内容】和【向wangEditor中添加内容】;
(3) 读取wangEditor中的内容;
html()方法,没有参数时,就是获取元素的html纯文本;(这儿可以参考下【jQuery获取、设置表单】,虽然这儿我们使用的不是jQuery,但是能够看到,这些东西都是相通的;)
(4) 设置wangEditor中的内容;
html()方法,有参数时,就是向元素中写入html纯文本;即,通过上面的内容,可以发现,wangEditor在设计的时候,借鉴了很多jQuery用法;
(5) 启动Tomcat,观察最终效果;
可以看到,wangEditor初始化、写入内容、读取内容,均没问题;
至此,wangEditor的最基本使用就OK了;有了这个基础后,就可以取开发后台的图书管理功能了;
实现wangEditor图片上传
说明:
(1) 本篇博客内容说明:【在后台系统,我们点击新增按钮后,会弹出新增图书对话框】→【该对话框中,包含一个wangEditor富文本编辑器】→【wangEditor富文本编辑器中,可以包含图片】→【我们点击对话框中的“点击提交”按钮后,会把当前图书的信息给提价到服务器】→【不过,本篇博客,只关心如何把wangEditor中的图片上传到服务器;暂不关心图书信息的其他内容】→【完整图书信息提交,的后端逻辑,将在下篇博客中介绍】;
(2) 本篇博客讲到Spring MVC的文件上传:
● Spring MVC在【后台系统四:【新增】功能;(FileUpload组件)】中介绍的Apache Commons FileUpload组件基础上,做了封装;
● 类似的【有关,表单提交格式、或,上传文件的内容】,以前遇到过两次:在【Kaptcha验证码功能应用到注册模块】中通过【data:$(“#frmLogin”).serialize()】,把表单的数据给序列化了;serialize()方法是JQuery中的ajax方法,其作用是编码表单元素集为字符串以便提交;然后,自己想起了【后台系统四:【新增】功能;(FileUpload组件)】这篇博客;这篇博客主要内容是【提交的表单的时候,涉及到了文件上传】,然后我们通过【enctype=“multipart/form-data”】设置表单的编码方式,以便能够上传文件;
一:本篇博客,开发内容说明;
在后台管理系统,当我们点击【添加】按钮后,会出现一个【包含wangEditor富文本编辑器的,弹出表单】;当我们点击【立即提交】后,会把图书的信息提交到服务器;
其中,因为wangEditor是富文本编辑器,其中的内容可能是图文混排内容;所以,如何把其中的图片上传到服务器上,是难点;
因此,我们要针对wangEditor,开发与之对应的【图片上传功能】;
二:前置准备:引入后台首页book.ftl;创建访问入口;观察效果;
1.引入后台管理系统的首页:book.ftl;
book.ftl:
说明:
(1) 这个book.ftl,和前面的【绘制后台首页UI布局】类似,都是使用LayUI的;
(2) 这个前端文件中,很多前端的功能都已经编写了; 我们与之对应的编写后端的功能即可;
(3) book.ftl,就是后台系统的图书管理首页;在book.ftl这一个界面上,我们可以完成对图书信息的增删改查操作;
2.创建MBookController类,编写访问book.ftl的入口;
MBookController:
说明:
(1) MBookController类说明:
3.启动Tomcat,访问后台的图书管理首页,去看下book.ftl;
当我们点击【添加】按钮后,会弹出【新增图书的对话框】;
三:wangEditor官方文档,对【上传图片】的文档说明;
四:正式开发wangEditor的【上传图片】功能;
1.后台管理系统的首页:book.ftl分析;
(1)book.ftl静态页面部分;
(2)book.ftl动态部分;
通过分析book.ftl,可知wangEditor图片文件上传地址为:【/management/book/upload】;即,我们应该在后端编写一个处理wangEditor图片上传的接口,而且该接口的url需要是【/management/book/upload】;
那么,我们在后端就要开发相应的接口;
2.在Spring MVC项目中,配置引入【Common FileUpload组件】,并配置:以使得Spring MVC具备文件上传的能力;
Spring MVC底层文件上传,是依赖于Apache提供的Common FileUpload组价;这部分,需要可以参考
【后台系统四:【新增】功能;(FileUpload组件)】中的内容;
(1)在pom.xml中,引入Common FileUpload组价的依赖;
老生常谈:引入新依赖后,如有需要,别忘了,把这个依赖添加到发布中去;
(2)在applicationContext.xml中配置,激活Spring MVC的文件上传处理功能;
其中设置“defaultEncoding”属性为UTF-8,意思是:在表单提交时,表单内容按UTF-8编码;这可以解决中文乱码问题;
结合【后台系统四:【新增】功能;(FileUpload组件)】,能够感受到,Spring MVC在前面基础内容的基础上,封装了文件上传功能;
至此,我们在Spring MVC项目中,就引入了FileUpload组件;然后,又因为Spring MVC基于Upload组件等原先的基础知识,作了进一步的封装;
所以,接下来,我们就可以在项目中,去进行文件上传了;
3.在MBookController类中,增加upload()方法,实现wangEditor中图片的上传;
说明:
(1) 【upload()方法的url】需要和【前端设置的wangEditor的图片提交地址】保持一致;
(2) 因为wangEditor,需要后端返回JSON字符串,以说明服务器是否处理成功;所以,upload()的返回值我们定成了Map;
(3) 使用MultipartFile接收wangEditor传过来的文件,而且需要设置一些@RequestParam;
(4) 在获取图片上传的地址时,需要用到HttpServletRequest原生对象,在参数中写上它;
(5) 拼凑图片文件上传地址,并将文件保存到指定的目录下;
transferTo()方法会抛异常,我们继续向上抛就行;
(6) 由于wangEditor上传图片时,当我们后端处理完了之后,需要通知wangEditor后台处理成功了;为此,我们需要按照wangEditor的要求,返回结果;
(7) 在【后台系统四:【新增】功能;(FileUpload组件)】中,我们要想上传文件,我们把前端<form表单的enctype属性,设置为了”multipart/form-data”;与这儿对比一下,能够感受到,Spring MVC在这些久知识上,做了封装;
4.启动Tomcat,观察效果;
而且,查看网页源代码,可以看到图片地址:
自然,在后端的相应地址上,是有这个图片文件的:
说明:
(1) 在啰嗦一下,上面的来龙去脉:
自此,新增图书中,比较复杂的wangEditor上传图片就OK了;下篇博客将要完全实现图书的新增功能;
完成图书的新增功能
说明:
(1) 本篇博客内容说明:
(2) 本博客的几个点:
● java中一款不错的HTML解析器:jsoup;
● 其实,目前来看,只要【和前端对接好接口,设置好url,明确了来回的数据格式】,单纯的开发后端的CRUD,其实工作量不大;
由此能够感受到,作为主栈是后端的开发者来说,CRUD比较简单;真正复杂和牛批的是:【底层数据库优化】、【并发】、【分布式】、【算法】、【引擎】、【设计模式】、【中间件】、【目前成熟框架的源码】、【计算机组成原理】、【网络协议】、【大数据】、【系统架构优化】等;
● 通过本篇博客的案例,也多少能明白,图文混排的内容,在后端是如何处理的、在数据库中是如何存储的;
一:前置分析
然后,需要注意,我们要求wangEditor最少需要传入一张图片;而且,其中的第一张图会默认作为该图书的封面;
之所以是【localhost/management/book/create】这个地址:下面给出说明:
表单提交的数据分析:
● 当我新增图书时,evaluation_score和evaluation_quantity都是0,这个很容易理解;
● 我们要求wangEditor最少需要传入一张图片;而且,其中的第一张图会默认作为该图书的封面;而wangEditor中的内容就是description,其实一段HTML片段;所以,description这个HTML片段中的,第一个img就是cover,这个需要我们在后端处理一下;为了能更好的解决这个需求,引入了java中一款不错的HTML解析器:jsoup;
二:后台接口开发;
1.在BookService接口中,定义一个新增图书的方法:createBook()方法;
2.在BookServiceImpl中,去实现createBook()方法;
附:jsoup简介,在工程中引入jsoup;
访问jsoup的官网:【https://jsoup.org/】;
在pom.xml中,引入jsoup依赖;
老生常谈的点:引入新依赖后,如有需要,记得添加到发布中去;
3.在MBookController类中,创建新增图书的方法:createBook()方法;
说明:
(1) url要对的上;
(2) 前端表单的输入项,就是针对Book来的,而且其命名符合Book属性;所以,后端可以用Book实体类去接收;
(3) 然后,就是补全Book的属性:其中用到了java中一款不错的HTML解析器:jsoup;
(4) 然后,就是调用BookService中定义的createBook方法;并根据前端的要求返回对应的code和mag信息;
(5) 还有一点就是,BookService的createBook()方法没有抛BussinessException异常,但为什么Controller这儿要捕获这个异常呐?:这一点前面说过,BookService的createBook()方法现在没抛BussinessException异常,不代表以后新业务需要来的时候不抛;;;所以,Controller这儿算是提前准备了一手;
4.运行效果;
继续执行:可以看到Book的主键ID也回填了:(背后,是Mybatis-Plus已经帮我们做了;)
放开断点,让其继续执行:底层数据库也没问题;
然后,在前台系统中,也能看到我们新增的那本图书;
至此,图书的新增功能就OK了;下篇博客要做的就是,在后台系统首页上,展示图书的数据表格;
后台图书列表显示
说明:
(1) 本篇博客内容说明:基于分页查询的策略,查询book表,并将查询结果显示在前端的table表格上;
(2) 本篇博客的分页查询:
● 后端,使用的是在【SSM整合Mybatis-Plus】中配置了Mybatis-Plus的分页插件;在【SSM整合Mybatis-Plus】中,第一次演示了Mybatis-Plus分页插件的使用;
● 前端,使用的是LayUI表格;关于layui表格的内容,第一次遇到是在【包括$(““)[0].reset();layui表格的设置,layui中弹出框附带数据的技巧等】;但不幸的是,layui已经停止维护了;目前主流开发中,前端也基本不使用LayUI;所以,本篇博客中的layui内容,没必要深究;能做到理解了就行;
(3) 本篇博客其实不难,还好,只要按照标准的SOP开发就行了;
一:前置说明;
1.layui的声明;
在
【包括$(““)[0].reset();layui表格的设置,layui中弹出框附带数据的技巧等)】我们详细介绍过LayUI表格的内容;(只是,当时在介绍layui表格的时候,没有开启分页;)
但是,layui项目已经停止维护;同时,在实际开发中,也很少使用layui,所以对于layui的内容没必要深究;同时,自己作为一个主栈是后端的开发者来说,目前没有必要深究前端的内容;而且,前端文件book.ftl,已经帮我们该准备的都准备好了;
所以,在这儿针对layui表格,只需要大致明白以下几点就够了:
(1) 首先,添加一个基础组件:table;(这个table后续会被转化为数据表格)
(2) 然后,初始化数据表格(对(1)中的table进行处理):此处主要是,初始化表格,设置表的列和数据的对应关系;
可以看到,其中的page属性我们设置为了true,即开启了属性;
通过访问前台book.ftl,也可以看到,layui表格发起了一个ajax请求:因为我们layui开启了分页,所以后面跟了两个参数【page】和【limit】;
上面的url对应的后端接口,还没有开发,我们接下来需要去开发;
2.后端的(基于Mybatis-Plus)的分页方法;
前面在开发前台系统的时候,我们在BookService中已经定义了一个分页方法;
而且,在BookServiceImpl中实现的时候,categoryId,order也是可以为null的;即paging()方法普适性很强;(由此其对参数的处理方式,可以看到,开发前台系统的时候,就预料到后台的需求了……这得需要开发经验和功力~~):
Mybatis-Plus的分页查询对象IPage很给力;
在【走了一遍Mybatis-Plus的流程】中,第一次演示了Mybatis-Plus分页插件的使用;如有需要,可以去参考;
二:正式开发;
1.在MBookController中,开发接收前台layui表格ajax请求的分页处理方法:list()方法;
说明:
(1) url要对上;
(2) 接收前台参数时,参数要对应上;
(3) 为了增加程序的健壮性,我们增加了对page和limit参数的判空处理;即,万一前台传过来的这俩数为null时,我们就给其赋默认值;
(4) n以为BookServiceImpl中的paging()方法的categoryId和order参数可以为空;而且,我们后台的这儿,也完全没有也不需要这个两个参数,所以我们在调用pagin()方法的时候,这个两个参数都设为了null;;(这也体现了paging()方法的通用性)
(5) 通过在【(包括$(““)[0].reset();layui表格的设置,layui中弹出框附带数据的技巧等)】可知,layui表格对后端返回数据的格式有要求;如有需要,可以去那篇博客中去参考;
2.启动Tomcat,观察效果;
通过结果,可以看到layui不仅表格显示数据很给力,其开启分页后,也很智能;
至此,后台图书列表分页显示,就开发完了;接下来就是开发【修改】和【删除】按钮对应的功能了;
三:【修改】和【删除】按钮,提前分析;
在下篇博客我们将实现【修改】功能;
图书修改更新功能
说明:
(1) 本篇博客内容:【修改】功能;
(2) 几点说明:
● 本篇博客前端部分,涉及到了大量的layui的内容;没必要深究,但要尽量做到了能不留盲点的自洽;
● 本篇博客讲到了更新操作的套路:【先查询原始数据】→【然后,在原始数据基础上,进行对应属性的调整】→【然后,再拿这个调整后的原始对象,去更新】;这个十分重要;
一:前置内容说明;
1.【修改】部分,主要包含两部分内容;
(1)第一部分: 点击【修改】按钮后,根据id去查询图书信息,回填到弹出的表单中;
(2)第二部分:当我们修改完了,点击【立即提交】后,向后端的update接口,提交数据,去更新 ;
2.前端内容分析;
(1) 第一部分: 点击【修改】按钮后,根据id去查询图书信息,回填到弹出的表单中;
(2)第二部分:当我们修改完了,点击【立即提交】后,向后端的update接口,提交数据 ;
前端的内容分析好了,接下来就是在后端开发与之对应的接口了;
二:正式开发;
1.完成上面【第一部分】的内容:在MBookController中,创建一个根据图书id查询图书信息的方法:selectById()方法;
说明:
(1) url要对应上,而且其需要使用路径变量去接收url中的参数;
有关路径变量,第一次遇到是在【RestController注解与路径变量】(使用@PathVariable注解来获取路径变量值);”)】;如有需要,可以去参考;
(2) 后端接口,根据前端需求返回数据就行了;
(3) 重启Tomcat,观察效果;
2.完成上面【第二部分】的内容:图书更新;
(1)在BookService接口中,定义更新图书的方法:updateBook()方法;
(2)在BookServiceImpl类中,去实现更新图书的方法:updateBook()方法;
(3)在MBookController中,创建更新的方法:updateBook()方法;(这儿,讲到了更新操作的一般操作策略,十分重要!!!)
说明:
(1) url要写对;
(2) 接收数据和返回数据,要符合前端要求;
(3) 更新的正确做法:
首先,不能直接拿前端传过来的对象去更新;
正确的做法是:先根据【前端传过来的对象的信息】,去数据库中查询【原始的对象信息】;然后,根据【前端传过来的对象的信息】,去更新【原始的对象信息】;然后,在拿这个修改过的原始对象,去更新数据库;
如果,我们直接拿前端传过来的对象去更新,轻则程序报错,重则数据产生混乱;
(4)启动Tomcat,观察效果;
至此,图书修改功能就完成了;下篇博客将介绍图书删除功能;
图书删除功能
说明:
(1) 本篇博客内容:【删除】功能;
(2) 本篇博客的内容,很简单,没什么好说的;
一:正式开发;
1.在BookService接口中,定义删除图书的方法:delete()方法;
2.在BookServiceImpl实现类中,去实现删除图书的方法:delete()方法;
说明:
(1) 删除方法,需要开启事务;
(2) 分别根据bookId删除,book表、evaluation表、member_read_state表的内容;
(3) 需要操作哪个表的时候,把该表对应的Mapper对象注入即可;
3.在MBookController中,创建删除图书的方法:deleteBook()方法;
说明:
(1) 这个方法没什么好说的,url和前端对应上;用到了路径变量;然后调用service层的方法;然后,根据前端的需求返回对应的信息即可;
4.启动Tomcat,观察效果;
然后,我们点击【删除】按钮;
其实,通过系统的日志,也能看到上述过程:(这儿就不啰嗦了)
至此,后台系统的图书增删改查,就都完成了;这些内容,十分基本,是必须要掌握的;
二:集成后台首页index.ftl;以及剩余任务说明……
1.把后台首页index.ftl,引入工程;
index.ftl:
2.创建ManagementController,编写后台首页的入口;
ManagementController:
说明:
(1) 这儿很简单,就是提供了后台首页index.ftl的访问入口;
(2) 只需要注意下一下,这类的url是【“/management”】,这可以很好的和前台系统区分开;
3.启动Tomcat,观察效果;
4.设置index.ftl,让其主体部分,显示图书管理页
5.重启Tomcat,观察效果:OK;
至此,MK书评网的,前后台基本开发完成了;
只是,还剩余【短评管理】和【后台登录】待开发……
SSM开发书评网总结
本篇博客是对【SSM开发书评网】的总结&归纳;SSM是真正贴合实际工作的第一个项目;是比较重要的;
说明:
(1) 目前觉得,就目前本专栏介绍了的内容来说,真正困难的是【数据库表设计】和【系统功能模块和结构设计】;
一:项目准备;
1. 在开发一个系统前,必须要有十分严格和明确的需求说明书;即,开发前,一定要搞清楚需求。
2. 开发前,要明确,采用什么技术栈。
这个项目主要使用SSM + Mybatis-Plus + layui + BootStrap + FreeMarker;
3. 创建与配置工程的步骤如下:
(1)创建工程:【创建一个就Maven的工程】→【把该工程设置为webapp工程】→【在IDEA中配置Tomcat】;
(2)配置Spring和Spring MVC:【引入spring-webmvc,FreeMarker,Jackson依赖】→【配置DispatcherServlet】→【启用Spring MVC注解开发模式】→【配置请求与响应字符集】→【配置FreeMarker】→【配置JSON序列化组件Jackson】;
(3)Spring与Mybatis整合:【引入spring-jdbc,mybatis,mybatis-spring,mysql-connector-java,druid依赖】→【配置数据源与druid连接池】→【配置SQLSessionFactoryBean对象】→【配置Mapper扫描器】→【创建mybatis-config.xml配置文件】;
(4)整合其他组件:【整合JUnit单元测试】→【整合logback日志】→【配置声明式事务】;
(5)SSM整合Mybatis-Plus:【引入Mybatis-Plus依赖】→【修改SQLSessionFactory的实现类】→【在mybatis-config.xml中,增加Mybatis-Plus的分页插件信息】;
(6)然后,因为项目前端部分需要使用BootStrap和LayUI等;所以,需要在项目中需要引入基础资源有:jQuery,BootStrap,LayUI,raty,Art-Template等;
上面的内容虽然麻烦,但很简单,跟着SOP做就行了;
4. 在数据库中创建一个逻辑空间;并根据项目业务需求,建表;
这一步需要相当的功力,目前自己似乎并不能很好的完成这个工作;
二:个人总结;
1. 遇到的小组件有:JS模板引擎Art-Template;星型评分插件raty;Kaptcha验证码组件;
wangEditor富文本编辑器;java中一款不错的HTML解析器:jsoup;
2. IDEA的几个快捷键:
创建【接口实现类】的快捷方式:【Alt + Enter】;
跳转到接口实现类的方法上:【Ctrl + Alt + 左键点击方法】;
创建测试类的快捷键:【Ctrl + Alt + T】
3. Mybatis-Plus很给力,但是对于一些复杂的操作,Mybatis-Plus是不行的;此时,我们还需要使用Mybatis的方式去解决;
4. 究竟后端方法是【渲染数据跳转页面】还是【返回JSON数据】以及【返回JSON数据的格式】,这是由前端的要求决定的;而前端的编写又是由业务逻辑的需求决定的;
作为主栈是后端的开发者来说,只要和前端对好接口,就可以把主要精力放在后端的开发上;
5. Mybatis-Plus的分页查询,很给力;其中的QueryWrapper查询构造器比较重要;
6. 在前端中,灵活使用“隐藏域”进行存值等操作,可以帮助开发;(这条还好,自己主栈不是前端;目前做到了解即可)
7. 我们在条件判断,或者前后端传值的时候(Controller接收前端的参数):增加非空的判断(如果前端传递值为空,就赋给默认值),能够提高程序的健壮性;
8. 自定义异常,作为一种【自己定义的警报器】还是很给力的;
9. 在Service部分,对于可能出现异常的地方,我们要主动捕获异常;
10. 即使Service部分没有抛出异常,为了全面考虑,我们在Controller调用的时候,也可以去捕获异常;(因为此时Service的方法没抛异常,不代表以后需要增加新逻辑的时,不会抛出异常)
11. 每次开发完Service或者Dao后,及时的测试很有必要;
12. 我们在使用静态资源时,最好使用绝对路径,而不要使用相对路径;(自然不排除,个别场景需要使用相对路径)
13. 一个新知识,或者说是一个骚操作:Mybatis-Plus的【@TableField(exist =
false)所谓关联查询时,给对象附加对象的策略:这可以让如Evaluation对象去承载evaluation表中没有对应字段的属性;
14. 在登录和注册功能处,使用了Kaptcha验证码组件;
15. 介绍了【注册】这种业务逻辑的开发套路;
16. 介绍了【登录】这种业务逻辑的开发套路;
17. 一种开发倾向:当我们的业务需要多表查询的时候,我们一般不在Dao层面使用多表查询的SQL语句来解决这个问题,而是在Service业务层面来化解,从而使得我们我们每次操作数据库的语句都是针对单表的;(PS:但是这点,我感觉不靠谱;)
18. Controller,Service,Dao在调用时,可以灵活一点,别那么死板,即希望具有一定的灵活性;(即AController可以去调用BService中定义的方法);
但是,究竟(一个要写在Controller中的)方法要写在哪个Controller中,这个能力需要慢慢加强;
19. 在Service层中控,即使是更新、删除、修改的方法,最好也要返回对应的更新、 删除 、修改的对象;
20. 重复点赞问题,自己想了一个笨笨的策略;但是,在实际项目中,如何解决这个业务,还不知道;
21. 讲到了Spring-Task定时任务的简单使用,其中也包括了Cron表达式和@Scheduled任务调度注解;
22. 介绍了wangEditor富文本编辑器;主要内容是,wangEditor富文本编辑器的图片上传;
23. 也展示了【layui表格 + Mybatis-Plus】,实现分页查询:使用体验不错;
24. 本篇博客讲到了更新操作的正确做法:【先查询原始数据】→【然后,在原始数据基础上,进行对应属性的调整】→【然后,再拿这个调整后的原始对象,去更新】;这点十分重要;
想到其他的,随时补充……