Spring之路(34)–使用xml配置Spring+SpringMVC+MyBatis(SSM)项目完整实例
2020/2/13 8:24:55
本文主要是介绍Spring之路(34)–使用xml配置Spring+SpringMVC+MyBatis(SSM)项目完整实例,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
概述
本篇介绍下如何使用xml配置SSM项目(如果要表达的更加严谨,其实除了xml配置,还有注解配置),并实现对单表(还是之前一直举例的blog表)增删改查操作。
因为需要配置的东西比较多,所以还是要简单的说下思路,先理顺了整体思路,才容易理解每个局部是在干什么。
- 首先需要新建一个
网站项目
,然后引入相关的jar包,因为SSM框架是别人封装好的,所以需要引入别人的jar。 - 因为是网站项目,所以需要配置
web.xml
,这个配置文件是网站项目配置文件。当网站启动时,会加载其中的配置。 - 需要配置
spring-config.xml
,我需要对spring容器进行配置,包括控制器组件、服务组件、数据库操作、数据源组件、MyBatis组件,都需要容器进行管理,spring配置是整个项目的核心配置。从此处可以看出MyBatis是通过spring集成进来的,在Spring一切皆组件的思想下,集成一个第三方框架是一个很简单事情。 - 配置
mybatis-config.xml
,此处是对mybatis进行配置,mybatis组件在进入容器管理时,携带该配置信息进入。spring负责管理mybatis组件,mybatis组件初始化时需要的配置信息就在mybatis-config.xml
。 - 依次开发数据库操作层、服务层、控制器层,前端视图页面,然后进行操作验证。
通过项目结构图了解下整体项目结构跟构建顺序:
1 新建项目
File-New-Other Project-Dynamic Web Project,建立一个动态网站项目,项目名称xmlssmdemo
2 导入jar包
除了spring相关的jar包(已经指示过多次不再具体指示),还需要导入下面的jar包:
commons-logging-1.2.jar
日志相关jackson-annotations-2.8.0.jar
json相关jackson-core-2.8.0.jar
json相关jackson-databind-2.8.0.jar
json相关mysql-connector-java-5.1.48.jar
mysql驱动druid-1.1.21.jar
数据库连接池mybatis-3.5.3.jar
mybatis相关mybatis-spring-2.0.3.jar
mybatis-spring相关
3 配置web.xml
当我们的网站项目启动时,会加载web.xml配置,此时我们要配置下DispatcherServlet
及其匹配的映射路径,同时引入spring容器的配置文件spring-config.xml
,具体如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>xmlssmdemo</display-name> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <!-- 引入spring-config.xml配置文件,该文件用来配置spring容器 --> <param-value>/WEB-INF/spring-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- 配置DispatcherServlet对应所有请求(*表示所有) --> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
4 配置spring-config.xml
很多开发者喜欢将spring配置保存到几个不同的xml配置文件中,本项目中由于我们的项目比较简单,所以直接放到一个配置文件中就好了,具体配置内容和配置顺序如下,请注意注释:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd"> <!-- 第一步,配置MyBatis用来操作数据,sqlSessionFactory就是MyBatis中用来操作数据库的 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 引入Mybatis的配置文件,MyBatis组件需要它 --> <property name="configLocation" value="classpath:org/maoge/xmlssmdemo/config/mybatis-config.xml" /> </bean> <!-- 第二步,配置数据源,可以看到sqlSessionFactory需要注入该数据源 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8"></property> <property name="username" value="root"></property> <property name="password" value="Easy@0122"></property> </bean> <!-- 第三步,将org.maoge.xmlssmdemo.dao包下的类注册为bean,注意此处是注册为MyBatis方式管理的可操作数据库的bean --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> <property name="basePackage" value="org.maoge.xmlssmdemo.dao" /> </bean> <!-- 第四步,扫描控制器层和服务层 --> <context:component-scan base-package="org.maoge.xmlssmdemo.controller" /> <context:component-scan base-package="org.maoge.xmlssmdemo.service" /> <!--第五步,开启通过注解配置访问路径与方法的匹配 --> <mvc:annotation-driven /> <!--第六步,配置静态资源映射 --> <mvc:resources mapping="/static/**" location="/static/" /> </beans>
简单的总结下,就是引入MyBaits组件,然后MyBatis是访问数据库的操作组件,还需要数据源,所以配置上数据源组件。在配置MyBatis组件时,还需要指定MyBatis组件的配置文件。
然后就是要扫描控制器层、服务层、数据库操作层,其中数据库操作层因为使用了MyBatis,所以需要使用一个定义好的MapperScannerConfigurer类型的bean来扫描该层。
最后就是常用配置了,开了注解驱动,然后配置了对静态资源访问的映射。
5、配置mybatis-config.xml
在配置spring.xml时,有如下一行代码:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 引入Mybatis的配置文件,MyBatis组件需要它 --> <property name="configLocation" value="classpath:org/maoge/xmlssmdemo/config/mybatis-config.xml" />
可以看出,Spring容器中有sqlSessionFactory这个bean组件,而该组件有个参数是mybatis-config.xml,也就是说Spring容器在注册sqlSessionFactory时,会加载mybatis-config.xml文件信息。
该xml文件制定了ORM元数据文件的位置,ORM元数据文件就是保存数据库表与Java对象之间映射关系的。mybatis-config.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> <mappers><!-- 映射器告诉MyBatis到哪里去找映射文件 --> <mapper resource="org/maoge/xmlssmdemo/config/BlogMapper.xml" /> </mappers> </configuration>
6、编写映射文件
再捋下子加载流程哈,别懵了。web项目启动–加载web.xml–加载配置的spring.xml–加载MyBatis的sqlSessionFactory组件–加载MyBatis配置文件mybatis-config.xml读取其中的映射信息。
所谓的映射,这个就是告诉我们的程序,数据库中的表blog对应Java类BlogDo,然后也得将表中的列与BlogDo中的属性对应关系描述出来。这样如果是由10行数据的表格,就对应size为10的List<BlogDo>
,这个必须得理解啊,如果这个理解不了,那…,还是先补补基础知识吧。
OK,下面我们来具体看下到底是怎么映射的哈,BlogMapper.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="org.maoge.xmlssmdemo.dao.BlogDao"> <select id="getById" parameterType="Long" resultType="org.maoge.xmlssmdemo.xdo.BlogDo"> select * from blog where id = #{id} </select> </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">
然后,看下面部分,namespace的值跟BlogDao类有一个对应,也就是说当执行BlogDao类中的方法时,会从该配置文件中找对应的配置来执行。
<mapper namespace="org.maoge.xmlssmdemo.dao.BlogDao">
然后,下面部分表示,当执行BlogDao类中的getById方法时,会转成下面对应的sql语句来执行,即执行select * from blog where id = #{id}
,同时#{id}
是一个占位符号,根据parameterType="Long"
,会把BlogDao类中的getById方法的Long类型的参数,注入到select * from blog where id = #{id}
的#{id}
的位置,也就是说如果执行getById(101),则会转换成执行sqlselect * from blog where id = 101
。
执行结果根据resultType="org.maoge.xmlssmdemo.xdo.BlogDo"
,也就是说列名会自动对应到BlogDo同名的属性中。
<select id="getById" parameterType="Long" resultType="org.maoge.xmlssmdemo.xdo.BlogDo"> select * from blog where id = #{id} </select>
所以通过映射文件,程序真正知道了当执行数据操作层(Dao)层方法时,该如何转换为执行的sql语句,又该如何将结果返回为Java对象。
7、开发各层逻辑代码
剩下的工作就都是类似的了,无非就是记忆下增删改查具体在BlogMapper.xml文件中的写法,此处我们贴下代码:
BlogMapper.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="org.maoge.xmlssmdemo.dao.BlogDao"> <!-- 获取一个 --> <select id="getById" parameterType="Long" resultType="org.maoge.xmlssmdemo.xdo.BlogDo"> select * from blog where id = #{id} </select> <!-- 获取列表 --> <select id="getList" resultType="org.maoge.xmlssmdemo.xdo.BlogDo"> select * from blog </select> <!-- 插入 --> <insert id="insert" parameterType="org.maoge.xmlssmdemo.xdo.BlogDo"> insert into blog(author,content,title)values(#{author},#{content},#{title}) </insert> <!-- 更新 --> <update id="update" parameterType="org.maoge.xmlssmdemo.xdo.BlogDo"> update blog set author=#{author},content=#{content},title=#{title} where id=#{id} </update> <!-- 删除 --> <delete id="delete" parameterType="Long"> delete from blog where id=#{id} </delete> </mapper>
然后BlogDao里面的方法名字与BlogMapper.xml中的id一一对应:
package org.maoge.xmlssmdemo.dao; import java.util.List; import org.maoge.xmlssmdemo.xdo.BlogDo; import org.springframework.stereotype.Repository; @Repository public interface BlogDao { BlogDo getById(Long id); List<BlogDo> getList(); int insert(BlogDo blog); int update(BlogDo blog); int delete(Long id); }
剩下的数据对象BlogDo、服务类BlogService、控制类BlogController与视图页面blog.html与之前一模一样了,直接贴代码:
package org.maoge.xmlssmdemo.xdo; /** * @theme 数据对象--博客 * @author maoge * @date 2020-01-29 */ public class BlogDo { private Long id; private String title; private String author; private String content; // 省略get get }
package org.maoge.xmlssmdemo.service; import java.util.List; import org.maoge.xmlssmdemo.dao.BlogDao; import org.maoge.xmlssmdemo.xdo.BlogDo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class BlogService { @Autowired private BlogDao blogDao; /** * 获取博客列表 */ public List<BlogDo> getBlogList() { return blogDao.getList(); } /** * 按id获取博客信息 */ public BlogDo getBlogById(Long id) { return blogDao.getById(id); } /** * 新增博客 */ public void addBlog(BlogDo blog) { blogDao.insert(blog); } /** * 根据博客id更新博客信息 */ public void updateBlog(BlogDo blog) { blogDao.update(blog); } /** * 根据博客id删除对应博客 */ public void deleteBlog(Long id) { blogDao.delete(id); } }
package org.maoge.xmlssmdemo.controller; import java.util.List; import org.maoge.xmlssmdemo.service.BlogService; import org.maoge.xmlssmdemo.xdo.BlogDo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; /** * @theme 控制器--博客 * @author maoge * @date 2020-01-28 */ @RestController // 通过该注解,第一将BlogController注册为控制器,第二将其中方法返回值转换为json public class BlogController { @Autowired // 自动装配blogService private BlogService blogService; /** * 查询博客信息 1、@GetMapping表示可以使用get方法请求该api * 2、"/blog/{id}"表示请求路径为/blog/{id}的形式,其中{id}为占位符 * 3、@PathVariable("id")表示将占位符{id}的值传递给id 4、也就是说/blog/123请求的话,会将123传递给参数id */ @GetMapping(value = "/blog/{id}") public BlogDo getOne(@PathVariable("id") long id) { return blogService.getBlogById(id); } /** * 查询博客列表,使用get方法 */ @GetMapping("/blog") public List<BlogDo> getList() { return blogService.getBlogList(); } /** * 新增博客 1、@PostMapping表示使用post方法 * 2、@RequestBody表示将请求中的json信息转换为BlogDo类型的对象信息,该转换也是由SpringMVC自动完成的 */ @PostMapping("/blog") public void add(@RequestBody BlogDo blog) { blogService.addBlog(blog); } /** * 修改博客 实际上此处也可以不在路径中传递id,而是整个使用json传递对象信息,但是我查询了一些文档,貌似使用路径传递id更加规范一些,此处不用纠结 */ @PutMapping("/blog/{id}") public void update(@PathVariable("id") long id, @RequestBody BlogDo blog) { // 修改指定id的博客信息 blog.setId(id); blogService.updateBlog(blog); } /** * 删除博客 */ @DeleteMapping("/blog/{id}") public void delete(@PathVariable("id") long id) { blogService.deleteBlog(id); } }
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <nav class="navbar navbar-inverse"> <div class="container-fluid"> <ul class="nav navbar-nav"> <li><a href="#" onclick="viewBlogs()">浏览博客</a></li> <li><a href="#" onclick="addBlog()">新增博客</a></li> </ul> </div> </nav> <table id="blogTable" class="table table-striped"> <tr> <th>ID</th> <th>标题</th> <th>作者</th> <th>操作</th> </tr> </table> <!-- 新增弹窗 --> <div id="blogAddModal" class="modal fade" tabindex="-1" role="dialog"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title">新增博客</h4> </div> <div class="modal-body" style="padding: 16px;"> <!-- 新增博客的表单 --> <form> <div class="form-group"> <label>标题</label> <input name="title" type="text" class="form-control"> </div> <div class="form-group"> <label>内容</label> <textarea name="content" class="form-control" rows="3"></textarea> </div> <div class="form-group"> <label>作者</label> <input name="author" type="text" class="form-control"> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" onclick="addBlogSubmit()">提交</button> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> </div> </div> </div> </div> <!-- 编辑弹窗 --> <div id="blogEditModal" class="modal fade" tabindex="-1" role="dialog"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title">编辑博客</h4> </div> <div class="modal-body" style="padding: 16px;"> <!-- 编辑博客的表单 --> <form> <div class="form-group"> <label>ID</label> <input name="id" type="text" class="form-control" readonly> </div> <div class="form-group"> <label>标题</label> <input name="title" type="text" class="form-control"> </div> <div class="form-group"> <label>内容</label> <textarea name="content" class="form-control" rows="3"></textarea> </div> <div class="form-group"> <label>作者</label> <input name="author" type="text" class="form-control"> </div> </form> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary" onclick="editBlogSubmit()">提交</button> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button> </div> </div> </div> </div> </body> <!--jQuery--> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"> </script> <script> //浏览博客 function viewBlogs() { var row = ""; //先清空表格 $('#blogTable').find("tr:gt(0)").remove(); $ .ajax({ type : "GET", url : "/xmlssmdemo/blog", dataType : "json", contentType : "application/json; charset=utf-8", success : function(res) { $ .each( res, function(i, v) { row = "<tr>"; row += "<td>" + v.id + "</td>"; row += "<td>" + v.title + "</td>"; row += "<td>" + v.author + "</td>"; row += "<td><a class='btn btn-primary btn-sm' href='#' onclick='editBlog(" + v.id + ")'>编辑</a>"; row += "<a class='btn btn-danger btn-sm' href='#' onclick='deleteBlog(" + v.id + ")'>删除</a></td>"; row += "</tr>"; $("#blogTable").append(row); }); }, error : function(err) { console.log(err); } }); } //新增 function addBlog() { $('#blogAddModal').modal('show'); } //新增提交 function addBlogSubmit() { var data = { id : '', title : $("#blogAddModal input[name='title']").val(), author : $("#blogAddModal input[name='author']").val(), content : $("#blogAddModal textarea[name='content']").val() }; $.ajax({ type : "POST", url : "/xmlssmdemo/blog", //dataType: "json", contentType : "application/json; charset=utf-8", data : JSON.stringify(data), //需要将对象转换为字符串提交 success : function() { //新增后重新加载 viewBlogs(); //关闭弹窗 $('#blogAddModal').modal('hide'); }, error : function(err) { console.log(err); } }); } //编辑 function editBlog(id) { //查询博客信息 $.ajax({ type : "GET", url : "/xmlssmdemo/blog/" + id, dataType : "json", contentType : "application/json; charset=utf-8", success : function(res) { console.log(res); //为编辑框赋值 $("#blogEditModal input[name='id']").val(res.id); $("#blogEditModal input[name='title']").val(res.title); $("#blogEditModal input[name='author']").val(res.author); $("#blogEditModal textarea[name='content']").val(res.content); //显示编辑弹窗 $('#blogEditModal').modal('show'); }, error : function(err) { console.log(err); } }); } //编辑提交 function editBlogSubmit() { var data = { id : $("#blogEditModal input[name='id']").val(), title : $("#blogEditModal input[name='title']").val(), author : $("#blogEditModal input[name='author']").val(), content : $("#blogEditModal textarea[name='content']").val() }; $.ajax({ type : "PUT", url : "/xmlssmdemo/blog/" + data.id, //dataType: "json", contentType : "application/json; charset=utf-8", data : JSON.stringify(data), //需要将对象转换为字符串提交 success : function() { //新增后重新加载 viewBlogs(); //关闭弹窗 $('#blogEditModal').modal('hide'); }, error : function(err) { console.log(err); } }); } //删除 function deleteBlog(id) { $.ajax({ type : "DELETE", url : "/xmlssmdemo/blog/" + id, //dataType: "json",//由于删除方法无返回值,所以此处注释掉 contentType : "application/json; charset=utf-8", success : function() { //删除后重新加载 viewBlogs(); }, error : function(err) { console.log(err); } }); } </script> </html>
总结
看明白了,基于Spring组件思想之后,我们只是把使用SpringJDBC实现的BlogDao替换为了使用MyBatis实现的BlogDao,其他的完全不需要变化。
同时之前SpringJDBC需要的数据源dataSource,与现在MyBatis使用的数据源dataSource组件配置完全一样。
Spring将功能、模块、类库等都化为了组件,召之即来挥之即去,非常类似于工业标准件的概念,大大提高了生产效率。
而为何我们广泛的采用了MyBatis、SpringJDBC等标准件,而不是自行开发的组件呢,就是因为大厂出品,经过千锤百炼的验证了,成本低效率高。
OVER。
这篇关于Spring之路(34)–使用xml配置Spring+SpringMVC+MyBatis(SSM)项目完整实例的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-09“2024鸿蒙零基础快速实战-仿抖音App开发(ArkTS版)”实战课程已上线
- 2024-05-09聊聊如何通过arthas-tunnel-server来远程管理所有需要arthas监控的应用
- 2024-05-09log4j2这么配就对了
- 2024-05-09nginx修改Content-Type
- 2024-05-09Redis多数据源,看这篇就够了
- 2024-05-09Google Chrome驱动程序 124.0.6367.62(正式版本)去哪下载?
- 2024-05-09有没有大佬知道这种数据应该怎么抓取呀?
- 2024-05-09这种运行结果里的10.100000001,怎么能最快改成10.1?
- 2024-05-09企业src漏洞挖掘-有意思的命令执行
- 2024-05-08阿里云域名注册流程,分享给第一次购买域名的新手站长!