SSM框架整合:个人图书管理系统项目实践
个人图书管理系统,一个简单的SSM整合练手项目,这篇文章展示的是SSM框架的整合思路,程度是将一个小 Demo 跑起来,具体实现请前往:
使用技术
Spring 5.x、SpringMVC + MyBatis 3.x
使用 mysql 8.x、lombok
使用 thymeleaf 模板引擎
HTML5、CSS、Javascript、Bootstrap 3.x、less
表设计
数据库表名: book_management,先把表给建起来,顺便插入点数据,以便后续测试。
图书表 (book)
字段 | 类型 | 描述 |
---|---|---|
id | int(11) | 书籍编号 |
isbn | char(13) | 国际标准书号 |
name | varchar(127) | 书籍名称 |
author | varchar(63) | 书籍作者 |
press | varchar(63) | 书籍出版社 |
price | double | 书籍定价 |
count | int(11) | 书籍数量 |
introduction | varchar(1023) | 书籍简介 |
category_id | int(11) | 书籍分类编号 |
create_time | timestap | 创建时间 |
update_time | timestap | 更新时间 |
图书分类表 (category)
字段 | 类型 | 描述 |
---|---|---|
id | int(11) | 分类编号 |
name | varchar(63) | 分类名称 |
description | varchar(255) | 分类描述 |
create_time | timestap | 创建时间 |
update_time | timestap | 更新时间 |
创建项目
创建 Maven Web 项目
先把 Hello World 给跑起来,确保项目没问题。有问题的可以参考这个:使用idea创建一个Maven java Web项目
编辑pom.xml
设置 maven 的一些属性
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
导入依赖
<dependencies>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!--Servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- thymeleaf -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<!--Spring、web-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<!-- spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
<!-- aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.5</version>
</dependency>
<!--mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<!--数据库连接池: c3p0; 常见数据源: druid c3p0 dbcp HiKariCP-->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.3</version>
</dependency>
</dependencies>
设置资源过滤
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
项目结构
依赖导入完后就可以编辑代码,项目的结构如下:
src
├ main
├ java
├ com.snwjas.ssmbook # 基础包名
├ controller # 控制器: xxController.java
├ mapper # mybatis mapper接口(dao层): xxMapper.java
├ xml # sql mapper: xxMapper.xml
├ model # 模型:诸如 PO / DTO / VO 等等
├ entity # 实体类: xxEntity.java
├ vo # 视图对象,返回给页面的渲染数据: xxVO.java
├ service # 服务接口:xxService.java
├ impl # 服务接口实现类:xxServiceImpl.java
├ resource # 放置配置文件,mybatis的xml文件也可以放这里
├ web # webapp
├ static # web 静态资源,如js / css / images
├ WEB-INF
├ templates # 放置模板引擎文件,如jsp / thymeleaf / freemarker...
├ test # 单元测试
├ java
├ com.snwjas.ssmbook
整合配置
使用 xml 配置完成 SSM 整合配置,配置文件置于 resources 目录下
数据源配置
数据库连接配置:database.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/book_management?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai
user=root
password=root
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>
<!-- 配置数据源交给Spring去做 -->
<settings>
<!--标准日志输出-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--驼峰命名识别-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!-- 别名 -->
<typeAliases>
<package name="com.snwjas.ssmbook.model.entity"/>
</typeAliases>
<!-- 这里配置 mapper xml 路径 -->
<mappers>
<!--<mapper resource="com/snwjas/ssmbook/mapper/xml/xxxMapper.xml"/>-->
</mappers>
</configuration>
持久层配置: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
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1.关联数据库配置文件 -->
<context:property-placeholder location="classpath:database.properties"/>
<!-- 2. 配置数据库连接池
c3p0: 自动化,自动化加载配置文件并且可以自动设置到对象中
-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 配置连接池属性 -->
<property name="driverClass" value="${driver}"/>
<property name="jdbcUrl" value="${url}"/>
<property name="user" value="${user}"/>
<property name="password" value="${password}"/>
<!-- c3p0连接池的私有属性 -->
<property name="maxPoolSize" value="30"/>
<property name="minPoolSize" value="10"/>
<!-- 关闭连接后不自动commit -->
<property name="autoCommitOnClose" value="false"/>
<!-- 获取连接超时时间 -->
<property name="checkoutTimeout" value="10000"/>
<!-- 当获取连接失败重试次数 -->
<property name="acquireRetryAttempts" value="2"/>
</bean>
<!-- 3.配置SqlSessionFactory对象 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据库连接池 -->
<property name="dataSource" ref="dataSource"/>
<!-- 配置MyBatis全局配置文件:mybatis-config.xml -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!-- 4.配置扫描 mapper 接口包,动态注入到spring容器中,不需要再实现BookMapper -->
<!-- 解释: https://www.cnblogs.com/jpfss/p/7799806.html -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入sqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!-- 给出需要扫描 mapper 接口包 -->
<property name="basePackage" value="com.snwjas.ssmbook.mapper"/>
</bean>
</beans>
业务层配置
spring-service.xml
,将 service 实现注入 bean,配置事务等。
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 1.扫描service包 -->
<context:component-scan base-package="com.snwjas.ssmbook.service"/>
<!-- 2.将所有业务类注入到Spring,使用配置或注解实现 -->
<!--<bean id="xxxService" class="com.snwjas.ssmbook.service.impl.xxxServiceImpl">
<constructor-arg name="xxxMapper" ref="xxxMapper"/>
</bean>-->
<!-- 3.配置声明式事务 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--注入数据源-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 4.aop事务支持 -->
<!--配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!--给哪些方法配置事务-->
<!--配置事务的传播特性:spring默认propagation="REQUIRED"-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.snwjas.ssmbook.mapper.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
</beans>
MVC配置
spring-mvc.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
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 1.扫描包:controller -->
<context:component-scan base-package="com.snwjas.ssmbook.controller"/>
<!-- 2.MVC注解驱动
在spring中一般采用@RequestMapping注解来完成映射关系,要想使@RequestMapping注解生效,
必须向上下文中注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter实例,
这两个实例分别在类级别和方法级别处理,而annotation-driven配置帮助我们自动完成上述两个实例的注入。
-->
<mvc:annotation-driven/>
<!-- 3.静态资源过滤 -->
<mvc:default-servlet-handler/>
<!-- 4. thymeleaf 模板解析器 -->
<bean id="templateResolver" class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/"/>
<property name="suffix" value=".html"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="order" value="1"/>
<property name="templateMode" value="HTML5"/>
<property name="cacheable" value="false"/>
</bean>
<!-- 配置模板引擎 -->
<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver"/>
</bean>
<!-- 配置视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</beans>
将配置添加到Spring上下文中
将以上 3 个配置文件导入到.xml
,然后将其添加到 Spring 上下文中
<?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-dao.xml"/>
<import resource="spring-service.xml"/>
<import resource="spring-mvc.xml"/>
</beans>
导入 spring 上下文:
配置web.xml
web/WEB-INF/web.xml
,初始化 applicationContext ,设置请求响应的编码过滤。
<?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适配器 DispatchServlet -->
<servlet>
<servlet-name>dispatcherServlet</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>dispatcherServlet</servlet-name>
<!-- 在SpringMVC中,
/ 匹配所有的页面,除了html页面
/* 匹配所有的页面,包括html页面
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 设置编码过滤器 -->
<filter>
<filter-name>characterEncodingFilter</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>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
到此 SSM 初步整合以完成,下面就可以正式写代码了。
编写代码
创建实体类
新建 book 表的实体类BookEntity
@Data
public class BookEntity {
private Integer id;
private String isbn;
private String name;
private String author;
private String press;
private Double price;
private Integer count;
private String introduction;
private Integer categoryId;
private LocalDateTime updateTime;
private LocalDateTime createTime;
}
创建 VO 类
新建 book 的视图对象类BookVO
,包装页面展示的数据。VO(View Object)实体对象,对 VO / DTO / PO / DAO 等概念不熟悉的,可以搜索了解一下。
@Data
@Accessors(chain = true)
public class BookVO {
private Integer id;
private String isbn;
private String name;
private String author;
private String press;
private Double price;
private Integer count;
private String introduction;
private Integer categoryId;
}
创建 MyBatis Mapper
创建BookMapper
接口
public interface BookMapper {
/**
* 根据id查询,返回一本Book
*/
BookEntity getBookById(@Param("bookId") int id);
}
创建BookMapper.xml
文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.snwjas.ssmbook.mapper.BookMapper">
<select id="getBookById" resultType="bookEntity">
select *
from book
where id = #{bookId};
</select>
</mapper>
在mybatis-config.xml
添加BookMapper.xml
<mappers>
<mapper resource="com/snwjas/ssmbook/mapper/xml/BookMapper.xml"/>
</mappers>
创建 Service
创建BookService
接口,根据业务需求,编写自己需要的接口
public interface BookService {
/**
* 根据id查询,返回一本Book
*/
BookVO getBookById(int id);
/**
* BookEntity 转 BookVO
*/
BookVO covertToBookVO(BookEntity bookEntity);
}
创建BookService
实现类BookServiceImpl
import com.snwjas.ssmbook.mapper.BookMapper;
import com.snwjas.ssmbook.model.entity.BookEntity;
import com.snwjas.ssmbook.model.vo.BookVO;
import com.snwjas.ssmbook.service.BookService;
import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.List;
public class BookServiceImpl implements BookService {
private final BookMapper mapper;
public BookServiceImpl(BookMapper bookMapper) {
this.mapper = bookMapper;
}
@Override
public BookVO getBookById(int id) {
BookEntity bookEntity = mapper.getBookById(id);
return covertToBookVO(bookEntity);
}
@Override
public BookVO covertToBookVO( BookEntity bookEntity) {
BookVO bookVO = new BookVO();
if(bookEntity != null) {
BeanUtils.copyProperties(bookEntity, bookVO);
}
return bookVO;
}
}
在spring-service.xml
中将业务类注入 bean 容器中
<bean id="bookService" class="com.snwjas.ssmbook.service.impl.BookServiceImpl">
<constructor-arg name="bookMapper" ref="bookMapper"/>
</bean>
单元测试
新建测试类MyTest
,注意建立完整的包名,如test.com.snwjas.ssmbook
,在自己的包名下放置测试类。
public class MyTest {
@Test
public void test() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) context.getBean("bookService");
System.out.println(bookService.getBookById(1));
}
}
能正常运行起来打印结果,说明项目OK了,可以编写网页代码了。
编写页面代码
创建书籍管理页面book.html
,该页面文件置于src/main/web/WEB-INF/templates
下,参考spring-mvc.xml
配置文件中对于 thymeleaf 模板引擎解析器的配置。
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>书籍管理</title>
</head>
<body>
<div>
<p>ISBN: <span th:text="${bookVO.isbn}"></span></p>
<p>书名:<span th:text="${bookVO.name}"></span></p>
<p>作者:<span th:text="${bookVO.author}"></span></p>
<p>出版社:<span th:text="${bookVO.press}"></span></p>
<p>分类编号:<span th:text="${bookVO.categoryId}"></span></p>
<p>定价:<span th:text="${bookVO.price}"></span></p>
<p>数量:<span th:text="${bookVO.count}"></span></p>
<p>描述:<span th:text="${bookVO.introduction}"></span></p>
</div>
</body>
</html>
创建控制器
创建书籍控制器BookController
@Controller
@RequestMapping("/book")
public class BookController {
@Autowired
private BookService bookService;
@GetMapping({"/get/{bookId}"})
public String list(Model model
, @PathVariable("bookId") Integer bookId) {
BookVO bookVO = bookService.getBookById(bookId);
model.addAttribute("bookVO", bookVO);
return "book";
}
}
测试运行
用 tomcat 运行项目,注意 tomcat 配置中 Deployment > Deploy at the server startum > Application context
的值,我这里为/
,则浏览器输入localhost:8080/book/get/1
,查看网页是否能正常打开,没有报错且结果显示正确。
到此,SSM框架的整合完成,后续往这个框架里填东西,增加功能即可。
总结
写下你的想法xxx