概述
本篇介绍下如何使用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,具体如下:
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">
xmlssmdemo
springmvc
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
/WEB-INF/spring-config.xml
1
springmvc
/*
4 配置spring-config.xml
很多开发者喜欢将spring配置保存到几个不同的xml配置文件中,本项目中由于我们的项目比较简单,所以直接放到一个配置文件中就好了,具体配置内容和配置顺序如下,请注意注释:
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">
class="org.mybatis.spring.SqlSessionFactoryBean">
value="classpath:org/maoge/xmlssmdemo/config/mybatis-config.xml" />
class="com.alibaba.druid.pool.DruidDataSource">
value="com.mysql.jdbc.Driver">
value="jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8">
value="sqlSessionFactory" />
base-package="org.maoge.xmlssmdemo.controller" />
base-package="org.maoge.xmlssmdemo.service" />
简单的总结下,就是引入MyBaits组件,然后MyBatis是访问数据库的操作组件,还需要数据源,所以配置上数据源组件。在配置MyBatis组件时,还需要指定MyBatis组件的配置文件。
然后就是要扫描控制器层、服务层、数据库操作层,其中数据库操作层因为使用了MyBatis,所以需要使用一个定义好的MapperScannerConfigurer类型的bean来扫描该层。
最后就是常用配置了,开了注解驱动,然后配置了对静态资源访问的映射。
5、配置mybatis-config.xml
在配置spring.xml时,有如下一行代码:
class="org.mybatis.spring.SqlSessionFactoryBean">
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代码如下:
/p>
"http://mybatis.org/dtd/mybatis-3-config.dtd">
6、编写映射文件
再捋下子加载流程哈,别懵了。web项目启动–加载web.xml–加载配置的spring.xml–加载MyBatis的sqlSessionFactory组件–加载MyBatis配置文件mybatis-config.xml读取其中的映射信息。
所谓的映射,这个就是告诉我们的程序,数据库中的表blog对应Java类BlogDo,然后也得将表中的列与BlogDo中的属性对应关系描述出来。这样如果是由10行数据的表格,就对应size为10的List,这个必须得理解啊,如果这个理解不了,那…,还是先补补基础知识吧。
OK,下面我们来具体看下到底是怎么映射的哈,BlogMapper.xml如下:
/p>
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
resultType="org.maoge.xmlssmdemo.xdo.BlogDo">
select * from blog where id = #{id}
首先下面这部分,是固定的头部,不用去管。
/p>
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
然后,看下面部分,namespace的值跟BlogDao类有一个对应,也就是说当执行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同名的属性中。
resultType="org.maoge.xmlssmdemo.xdo.BlogDo">
select * from blog where id = #{id}
所以通过映射文件,程序真正知道了当执行数据操作层(Dao)层方法时,该如何转换为执行的sql语句,又该如何将结果返回为Java对象。
7、开发各层逻辑代码
剩下的工作就都是类似的了,无非就是记忆下增删改查具体在BlogMapper.xml文件中的写法,此处我们贴下代码:
BlogMapper.xml代码
/p>
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
resultType="org.maoge.xmlssmdemo.xdo.BlogDo">
select * from blog where id = #{id}
resultType="org.maoge.xmlssmdemo.xdo.BlogDo">
select * from blog
parameterType="org.maoge.xmlssmdemo.xdo.BlogDo">
insert into
blog(author,content,title)values(#{author},#{content},#{title})
parameterType="org.maoge.xmlssmdemo.xdo.BlogDo">
update blog set
author=#{author},content=#{content},title=#{title} where
id=#{id}
delete from blog where
id=#{id}
然后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 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 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 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);
}
}
href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
crossorigin="anonymous">
ID | 标题 | 作者 | 操作 |
---|
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
crossorigin="anonymous">
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 = "
";row += "
" + v.id + "";row += "
" + v.title + "";row += "
" + v.author + "";row += "
编辑";row += "删除
";row += "
";$("#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);
}
});
}
总结
看明白了,基于Spring组件思想之后,我们只是把使用SpringJDBC实现的BlogDao替换为了使用MyBatis实现的BlogDao,其他的完全不需要变化。
同时之前SpringJDBC需要的数据源dataSource,与现在MyBatis使用的数据源dataSource组件配置完全一样。
Spring将功能、模块、类库等都化为了组件,召之即来挥之即去,非常类似于工业标准件的概念,大大提高了生产效率。
而为何我们广泛的采用了MyBatis、SpringJDBC等标准件,而不是自行开发的组件呢,就是因为大厂出品,经过千锤百炼的验证了,成本低效率高。
OVER。