学习完了Spring、SpringMVC、MyBatis的大部分相关内容后,我们来整合一个SSM框架来强化这段时间的学习认知,除了主线任务,还涉及到事务实现、日志AOP实现、MyBatis日志实现、并且在主线任务中创建各个层的实体类,当然因为比较简单,实体类的属性其实都一样,但是为了项目的完整性,一个都不能少。最后我们知道框架都有注解+配置的实现方式,我们会在适合的模块用适合的方式,例如MyBatis就使用配置好一些,Spring的AOP日志实现使用配置好一些,其它的都是使用注解好些,也就是我们会使用注解+配置的混合开发模式。
创建一个新项目
首先我们创建一个新的项目,名称是ssm-frame:
1 项目结构规划
项目整体结构如下:
2 Maven坐标导入
我们统一导入所有需要的Maven坐标,每个需要的模块我会用注释标识:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>ssm-frame</artifactId>
<version>1.0-SNAPSHOT</version>
<name>ssm-frame</name>
<packaging>war</packaging>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<junit.version>5.7.1</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.18</version>
</dependency>
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.32</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.3.1</version>
</plugin>
</plugins>
</build>
</project>
3 数据库关系表创建
创建person表,并插入几条数据:
MyBatis框架实现
接下来我们实现下MyBatis框架,按照如下的步骤实现:
1 domain实体类创建(PO)
首先我们需要创建一个持久化实体
Person
package com.example.ssm_frame.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private int id;
private String username;
private String password;
private int age;
private int phone;
private String email;
private String hobby;
}
2 PersonDao接口创建
然后创建两个接口方法,用来操作person表数据
PersonDao
package com.example.ssm_frame.dao;
import com.example.ssm_frame.model.Person;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface PersonDao {
List<Person> getPersonList();
int addPerson(Person person);
}
3 personMapper.xml映射文件编写
绑定personMapper.xml文件如下:
personMapper.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.example.ssm_frame.dao.PersonDao">
<select id="getPersonList" resultType="com.example.ssm_frame.model.Person">
select * from person
</select>
<insert id="addPerson" parameterType="com.example.ssm_frame.model.Person" >
insert into person (id,username,password,age,phone,email,hobby) values (#{id},#{username},#{password},#{age},#{phone},#{email},#{hobby})
</insert>
</mapper>
4 db.properties及日志配置编写
我们需要给数据库绑定访问属性:
db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username=root
password=root
然后我们需要配置相关日志:
log4j.properties
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
# 设置日志输出级别以及输出目的地,可以设置多个输出目的地,开发环境下,日志级别要设置成DEBUG或者ERROR
# 前面写日志级别,逗号后面写输出目的地
# log4j.rootLogger = [level],appenderName1,appenderName2,…
log4j.rootLogger=Debug,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
# 输出到控制台
log4j.appender.console.Target = System.out
# 指定控制台输出日志级别
log4j.appender.console.Threshold=DEBUG
# 默认值是 true, 表示是否立即输出
log4j.appender.console.ImmediateFlush = true
# 设置编码方式
log4j.appender.console.Encoding = UTF-8
# 日志输出布局
log4j.appender.console.layout = org.apache.log4j.PatternLayout
# 如果日志输出布局为PatternLayout 自定义级别,需要使用ConversionPattern指定输出格式
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
# 指定输出文件路径
log4j.appender.file.File=./log/tml.log
# 指定单个日志文件最大值
log4j.appender.file.MaxFileSize=10mb
# 指定输出日志级别
log4j.appender.file.Threshold=DEBUG
# 默认值是 true, 表示是否立即输出
log4j.appender.file.ImmediateFlush = true
# 设置编码方式
log4j.appender.file.Encoding = UTF-8
# 日志输出布局
log4j.appender.file.layout=org.apache.log4j.PatternLayout
# 如果日志输出布局为PatternLayout 自定义级别,需要使用ConversionPattern指定输出格式
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sq1.PreparedStatement=DEBUG
5 mybatis-config.xml核心配置编写
我们需要配置核心的mybatis配置文件:
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>
<properties resource="properties/db.properties"/>
<settings>
<setting name="logImpl" value="log4j"/>
<setting name="cacheEnabled" value="true"/>
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mappers/personMapper.xml"/>
</mappers>
</configuration>
6 spring-dao.xml整合配置编写
然后我们需要将MyBatis的相关配置整合到Spring中,所以SqlSession的创建及Mapper对象的创建都托管给了Spring:
spring-dao.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"
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 ">
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.example.ssm_frame.dao"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="myDataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<context:property-placeholder location="classpath:properties/db.properties" system-properties-mode="NEVER"/>
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</bean>
</beans>
Spring框架实现
接下来我们实现下Spring框架,按照如下步骤。
1 数据传输类创建(DTO)
理论上DTO和PO不同,需要做转换,但是这里我们项目比较简单,所以还用之前的Person
2 PersonService接口创建
然后我们需要创建PersonService。
PersonService
package com.example.ssm_frame.service;
import com.example.ssm_frame.model.Person;
import java.util.List;
public interface PersonService {
List<Person> getPersonList();
int addAndSendPerson(Person person);
}
3 PersonServiceImpl实现类创建
依据PersonService实现PersonServiceImpl,这里我们使用自动装配调用Dao层自动生成的Mapper对象。
PersonServiceImpl
package com.example.ssm_frame.serviceImpl;
import com.example.ssm_frame.dao.PersonDao;
import com.example.ssm_frame.model.Person;
import com.example.ssm_frame.service.PersonService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class PersonServiceImpl implements PersonService {
@Resource
private PersonDao personDao;
@Override
public List<Person> getPersonList() {
List<Person> personList=personDao.getPersonList();
for (Person person : personList) {
System.out.println(person);
}
return personList;
}
@Override
@Transactional
public int addAndSendPerson(Person person) {
int result=personDao.addPerson(person);
this.sendMessage(person);
return result;
}
public void sendMessage(Person person){
System.out.println("人员新增到下游系统失败"+person);
throw new RuntimeException();
}
}
4 日志监控AOP类创建
我们需要用AOP实现方法前后的记录:
LogAop
package com.example.ssm_frame.aop;
import java.time.LocalDateTime;
public class LogAop {
public void beforeLog() {
System.out.println("日志记录开始"+ LocalDateTime.now());
}
public void afterLog() {
System.out.println("日志记录结束"+ LocalDateTime.now().plusMinutes(5));
}
}
5 applicationContext.xml核心配置编写
我们需要配置核心的启动配置文件,当然现在为空,最后我们再整合
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
6 spring-service.xml整合配置编写
然后我们配置下spring-service.xml来实现事务管理和日志管理
spring-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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.example.ssm_frame.serviceImpl" />
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="myDataSource" />
</bean>
<bean id="logAop" class="com.example.ssm_frame.aop.LogAop"></bean>
<aop:config proxy-target-class="true">
<aop:aspect ref="logAop">
<aop:pointcut id="logPointCut" expression="execution(* com.example.ssm_frame.service..*.*(..))"/>
<aop:before pointcut-ref="logPointCut" method="beforeLog"/>
<aop:after pointcut-ref="logPointCut" method="afterLog"/>
</aop:aspect>
</aop:config>
</beans>
SpringMVC框架实现
接下来我们开始配置SpringMVC框架以及整合配置文件。
1 视图对象类创建(VO)
理论上VO和PO不同,需要做转换,但是这里我们项目比较简单,所以还用之前的Person
2 控制器PersonController类创建
我们来配置中心控制器,并自动装配Service层的实现,调用方法获取结果传输到JSP页面。
PersonController
package com.example.ssm_frame.controller;
import com.example.ssm_frame.model.Person;
import com.example.ssm_frame.serviceImpl.PersonServiceImpl;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.annotation.Resource;
import java.util.List;
@Controller
@RequestMapping("/person")
public class PersonController {
@Resource
private PersonServiceImpl personServiceImpl;
@RequestMapping("getPersonList")
public String requestDispatch(@RequestParam("username") String username, ModelMap modelMap) {
if(username.equals("root")){
List<Person> personList=personServiceImpl.getPersonList();
modelMap.addAttribute("personList", personList);
}
return "list";
}
}
注意SpringMVC默认的作用域时一次request,无论是Model还是ModelMap,放置的上下文作用域都是一次request。
3 视图页list.jsp创建
然后我们编写写列表信息:
list.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page pageEncoding="UTF-8" %>
<html>
<head>
<title>人员列表</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 引入 Bootstrap -->
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12 column">
<div class="page-header">
<h1>
<small>人员列表 —— 显示所有人员</small>
</h1>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-md-12 column">
<table class="table table-hover table-striped">
<thead>
<tr>
<th>用户名</th>
<th>年龄</th>
<th>手机号</th>
<th>邮箱</th>
<th>兴趣爱好</th>
</tr>
</thead>
<tbody>
<c:forEach var="person" items="${requestScope.get('personList')}">
<tr>
<td>${person.getUsername()}</td>
<td>${person.getAge()}</td>
<td>${person.getPhone()}</td>
<td>${person.getEmail()}</td>
<td>${person.getHobby()}</td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div>
4 web.xml配置注册DispatcherServlet
然后我们将中心控制器注册到web.xml,用来启动时读取:
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">
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encodingFilter</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>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<session-config>
<session-timeout>15</session-timeout>
</session-config>
</web-app>
5 springmvc-servlet.xml核心配置编写
springmvc-servlet.xml 核心配置我们用spring-mvc.xml 来替代。
6 spring-mvc.xml整合配置编写
MVC的核心配置即是springmvc-servlet.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.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.example.ssm_frame.controller"/>
<mvc:default-servlet-handler />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
SSM框架整合
三个框架的主体都编写完毕后,我们来整合框架并做测试
1 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="spring-configs/spring-dao.xml"/>
<import resource="spring-configs/spring-service.xml"/>
<import resource="spring-configs/spring-mvc.xml"/>
</beans>
2 配置Tomcat服务器
然后我们配置Tomcat服务器:
3 启动服务器并进行测试
最后我们在浏览器请求访问然后看展示的效果: 同时通过日志我们从后台也能看到执行过程:
总结一下
这样就整合完成了SSM框架用来实现了一个简单的需求,事实上无论是早年间的Servlet+JSP+JDBC或是后来的SSH框架直至今天的SSM框架,其完成的功能都是固定的,例如JDBC、Hibernate和MyBatis完成的工作是数据持久化,它们都需要处理数据缓存、连接池、结果集映射、查询参数绑定等问题,但随着技术的发展,实现的成本越来越低;Servlet、Struts和SpringMVC都充当了(中心)控制器的功能,它们都需要处理事务、文件上传下载、请求转发、重定向、过滤器、监听器等问题,同样随着技术的发展,实现的成本越来越低;Spring呢作为后来的整合老大哥,通过IOC技术接管了各种类和各种框架,让所有的框架从大杂烩成为了一体,更好的服务于开发者。技术从来就是用来解决业务问题的,哪种实现方式更简单,我们用哪种,但不仅要知道怎么用还要知道为什么用,这才是重点。
|