Spring之路(35)–使用JavaConfig配置Spring+SpringMVC+MyBatis(SSM)项目完整实例

10 阅读 作者:慕课熊猫 2020-05-09

背景

本篇的表面目的,就时去掉烦人的xml文件,全部使用JavaConfig(如果要表达的更加严谨,其实除了JavaConfig配置,还有注解配置)开发一个SSM项目。

真实目的是演示,xml、注解、JavaConfig只是配置bean的不同方式,功能目的是一致的。在本系列文章中,我曾经很多次做过一件事——将xml+注解配置的SSM项目翻译为JavaConfig+注解配置的SSM项目,目的就是让大家深刻体会这一点。理解三种配置方式殊途同归,是学习和理解Spring的基石

实际上SpringBoot跟全部使用JavaConfig+注解配置的SSM项目,高度相似,除了更加简洁了点,技术上没有多少新增的内容。所以如果Spring基础掌握的好,学习SpringBoot,简直就是不费吹灰之力!当然,后续Spring之路系列完结之后,我也会继续推出SpringBoot之路,敬请期待。

本篇讲述方式

我们会通过逐一对比的方式,逐一对比上篇文章中xml配置的各个步骤,然后将步骤修改为JavaConfig配置,以便于大家体会理解。坐稳了老弟,开整~~~~

1 新建项目

原来:
File-New-Other Project-Dynamic Web Project,建立一个动态网站项目,项目名称xmlssmdemo
修改:
项目名称改为jcssmdemo,jc为JavaConfig缩写,因为javaconfigssmdemo这个项目名称实在是太长了。

2 导入jar包

原来:
除了spring相关的jar包(已经指示过多次不再具体指示),还需要导入下面的jar包:

  1. commons-logging-1.2.jar 日志相关
  2. jackson-annotations-2.8.0.jar json相关
  3. jackson-core-2.8.0.jar json相关
  4. jackson-databind-2.8.0.jar json相关
  5. mysql-connector-java-5.1.48.jar mysql驱动
  6. druid-1.1.21.jar 数据库连接池
  7. mybatis-3.5.3.jar mybatis相关
  8. mybatis-spring-2.0.3.jar mybatis-spring相关

修改:这一步不需要修改

3 配置web项目

原来:

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

修改:
通过WebInit引导web项目加载,指定Spring容器的配置类为SpringConfig.class,注意WebInit本身并不是Spring容器的组件,而是通过继承AbstractAnnotationConfigDispatcherServletInitializer实现引导容器加载的作用。

package org.maoge.jcssmdemo;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
	@Override
	protected Class<?>[] getRootConfigClasses() {
		return null;
	}
	@Override
	protected Class<?>[] getServletConfigClasses() {
		// <!-- 引入SpringConfig配置类,该类用来配置spring容器 -->
		return new Class[] { SpringConfig.class };
	}
	@Override
	protected String[] getServletMappings() {
		// <!-- 配置DispatcherServlet对应所有请求(*表示所有) -->
		return new String[] { "/*" };
	}
}

4 配置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">
</beans>

改为:

package org.maoge.jcssmdemo;
import org.springframework.context.annotation.Configuration;
@Configuration // 表明该类是一个Spring配置类
public class SpringConfig {
}

注意这两个都是对Spring容器配置的描述,没啥功能区别,但是很明显类的方式更加简洁点。

修改sqlSessionFactory配置

原来

	<!-- 第一步,配置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>

改为

  	@Bean // 配置sqlSessionFactory
	public SqlSessionFactoryBean sqlSessionFactory() {
		SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
		sqlSessionFactory.setDataSource(dataSource());
		// <!-- 引入Mybatis的配置文件,MyBatis组件需要它 -->
		Resource resource = new ClassPathResource("org/maoge/jcssmdemo/config/mybatis-config.xml");
		sqlSessionFactory.setConfigLocation(resource);
		return sqlSessionFactory;
	}

可以看出没啥区别,一个是xml定义bean,一个是通过方法添加@Bean注册bean;一个是通过property标签注入依赖项,一个是通过setter方法注入依赖项。

修改dataSource配置

原来

  	<!-- 第二步,配置数据源,可以看到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&amp;characterEncoding=utf-8"></property>
		<property name="username" value="root"></property>
		<property name="password" value="xxx"></property>
	</bean>

改为

	@Bean // 配置数据源
	public DataSource dataSource() {
		DruidDataSource dataSource = new DruidDataSource();
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8");
		dataSource.setUsername("root");
		dataSource.setPassword("xxx");
		return dataSource;
	}

没啥好说的,一个意思。

修改MapperScannerConfigurer配置

原来

	<!-- 第三步,将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>

改为

	@Bean
	public MapperScannerConfigurer initMapperScannerConfigurer() {
		MapperScannerConfigurer msc = new MapperScannerConfigurer();
		msc.setSqlSessionFactoryBeanName("sqlSessionFactory");
		// 扫描包
		msc.setBasePackage("org.maoge.jcssmdemo.dao");
		return msc;
	}

没啥好说的,一个意思。

修改扫描包

原来

	<!-- 第四步,扫描控制器层和服务层 -->
	<context:component-scan
		base-package="org.maoge.xmlssmdemo.controller" />
	<context:component-scan
		base-package="org.maoge.xmlssmdemo.service" />

改为

@Configuration // 表明该类是一个Spring配置类
@ComponentScan({ "org.maoge.jcssmdemo.controller", "org.maoge.jcssmdemo.service" }) // 对应第四步,扫描包
public class SpringConfig extends WebMvcConfigurerAdapter {
}

通过标签指定扫描,改为了通过注解。

其他配置

剩下的两个配置通过添加@EnableWebMvc注解和addResourceHandlers方法实现,此处我们给出配置类的最终完整代码:

原来

	<!--第五步,开启通过注解配置访问路径与方法的匹配 -->
	<mvc:annotation-driven />
	<!--第六步,配置静态资源映射 -->
	<mvc:resources mapping="/static/**" location="/static/" />

新的配置类完整代码

package org.maoge.jcssmdemo;

import javax.sql.DataSource;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.alibaba.druid.pool.DruidDataSource;

@Configuration // 表明该类是一个Spring配置类
@ComponentScan({ "org.maoge.jcssmdemo.controller", "org.maoge.jcssmdemo.service" }) // 对应第四步,扫描包
@EnableWebMvc // 实现SpringMVC功能
public class SpringConfig extends WebMvcConfigurerAdapter {
	@Bean // 配置sqlSessionFactory
	public SqlSessionFactoryBean sqlSessionFactory() {
		SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
		sqlSessionFactory.setDataSource(dataSource());
		// <!-- 引入Mybatis的配置文件,MyBatis组件需要它 -->
		Resource resource = new ClassPathResource("org/maoge/jcssmdemo/config/mybatis-config.xml");
		sqlSessionFactory.setConfigLocation(resource);
		return sqlSessionFactory;
	}
	@Bean // 配置数据源
	public DataSource dataSource() {
		DruidDataSource dataSource = new DruidDataSource();
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/myblog?useUnicode=true&characterEncoding=utf-8");
		dataSource.setUsername("root");
		dataSource.setPassword("xxx");
		return dataSource;
	}
	@Bean
	public MapperScannerConfigurer initMapperScannerConfigurer() {
		MapperScannerConfigurer msc = new MapperScannerConfigurer();
		msc.setSqlSessionFactoryBeanName("sqlSessionFactory");
		// 扫描包
		msc.setBasePackage("org.maoge.jcssmdemo.dao");
		return msc;
	}
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/static/**").addResourceLocations("/static/");
	}
}

注意以下部分就跟之前基本一样了,除了项目名称和包名称,具体如下:


5、配置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/jcssmdemo/config/BlogMapper.xml" />
	</mappers>
</configuration> 

6、编写映射文件

<?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.jcssmdemo.dao.BlogDao">
	<!-- 获取一个 -->
	<select id="getById" parameterType="Long"
		resultType="org.maoge.jcssmdemo.xdo.BlogDo">
		select * from blog where id = #{id}
	</select>
	<!-- 获取列表 -->
	<select id="getList"
		resultType="org.maoge.jcssmdemo.xdo.BlogDo">
		select * from blog
	</select>
	<!-- 插入 -->
	<insert id="insert"
		parameterType="org.maoge.jcssmdemo.xdo.BlogDo">
		insert into
		blog(author,content,title)values(#{author},#{content},#{title})
	</insert>
	<!-- 更新 -->
	<update id="update"
		parameterType="org.maoge.jcssmdemo.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>

7、开发各层逻辑代码

package org.maoge.jcssmdemo.dao;

import java.util.List;

import org.maoge.jcssmdemo.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);
}

package org.maoge.jcssmdemo.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.jcssmdemo.service;

import java.util.List;

import org.maoge.jcssmdemo.dao.BlogDao;
import org.maoge.jcssmdemo.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.jcssmdemo.controller;

import java.util.List;

import org.maoge.jcssmdemo.service.BlogService;
import org.maoge.jcssmdemo.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.Requ                            
原文地址:https://www.imooc.com/article/300617
广告一下
热门教程
PHP7报A non well formed numeric value encountered 0
Linux系统下关闭mongodb的几种命令分享 0
mongodb删除数据、删除集合、删除数据库的命令 0
Git&Github极速入门与攻坚实战课程 0
python爬虫教程使用Django和scrapy实现 0
libnetsnmpmibs.so.31: cannot open shared object file 0
数据结构和算法视频教程 0
redis的hash结构怎么删除数据呢? 0
C++和LUA解析器的数据交互实战视频 0
mongodb errmsg" : "too many users are authenticated 0
C++基础入门视频教程 0
用30个小时精通C++视频教程可能吗? 0
C++分布式多线程游戏服务器开发视频教程socket tcp boost库 0
C++培训教程就业班教程 0
layui的util工具格式时间戳为字符串 0
C++实战教程之远程桌面远程控制实战 1
网络安全培训视频教程 0
LINUX_C++软件工程师视频教程高级项目实战 0
C++高级数据结构与算法视频教程 0
跨域问题很头疼?通过配置nginx轻松解决ajax跨域问题 0
相关文章
【译】JavaScript数据结构(3):单向链表与双向链表 16
10个JavaScript难点 16
【译】苹果拒绝支持PWA,有损Web的未来 16
iView 一周年了,同时发布了 2.0 正式版,但这只是开始... 16
nodejs+mongodb构建一个简单登录注册功能 16
【译】JavaScript数据结构(4):树 16
组件化开发与黑箱 16
TypeScript - 不止稳,而且快 16
webpack3+anujs+ReactCSSTransitionGroup 16
原生js实现图片放大镜效果 16
WEB缓存探究第二弹——实战 16
纯笔记:vfork 的一些使用场景(顺便讲一下 fork 的原理) 16
Android APP 内部捐赠实现(支付宝&amp;微信) 16
WKWebView 的一些小总结 16
模型评价(一) AUC大法 16
开始使用GraphQL 16
Webpack模块化原理简析 16
gulp使用问题记录 16
使用Angular4动画为页面添彩 16
Python27 Matplotlib (win64 python2.7) 安装及简单使用 16