SSM整合项目
需求:实现一个图书管理系统,有增删改查、搜索功能
1、创建数据库和数据表
CREATE DATABASE `ssm_book`;
USE `ssm_book`;
CREATE TABLE `bookshelf`(
`id` INT(4) PRIMARY KEY NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`count` INT(10) NOT NULL,
`author` VARCHAR(20) NOT NULL,
`price` INT(10) NOT NULL
)ENGINE=INNODB CHARSET=utf8;
INSERT INTO `bookshelf`(`id`,`name`,`count`,`author`,`price`) VALUES
(1,'盗墓笔记',8,'南派三叔',45),
(2,'鬼吹灯',4,'天下霸唱',50),
(3,'大泼猴',1,'甲鱼不是龟',50),
(4,'剑来',1,'烽火戏诸侯',60);
2、准备工作
-
导入依赖
<dependencies> <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.0.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.20</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <!--spring操作数据库--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.0.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.5</version> </dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> <!--数据库连接池--> <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 --> <dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
-
划分基础包结构
- 创建基础配置文件
3、Mapper层——Mybatis
-
写实体类
package com.xiaojing.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Book { private int id; private String name; private int count; private String author; private int price; }
-
操作数据库dao接口
package com.xiaojing.mapper; import com.xiaojing.pojo.Book; import java.util.List; public interface BookMapper { /*CRUD*/ int addBook(Book book); int deleteBookByid(int id); Book queryBookById(int id); int updateBook(Book book); List<Book> queryAllBook(); }
-
写Mapper.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> <insert id="addBook" parameterType="book"> insert into ssm_book.book(`name`,`count`,`author`,`price`) values (#{name},#{count},#{author},#{price}) </insert> <delete id="deleteBookByid"> delete from ssm_book.book where id=#{id} </delete> <select id="queryBookById" resultType="book"> select from ssm_book.book where id=#{id} </select> <update id="updateBook" parameterType="book"> update ssm_book.book set `name`=#{name},`count`=#{count},`author`=#{author},`price`=#{price} where `id`=#{id} </update> <select id="queryAllBook" resultType="book"> select * from ssm_book.book </select> </mapper>
4、Service层——Spring
一般xml来管理需要注册的bean,属性的注入使用注解
-
写spring-mapper.xml
<?xml version="1.0" encoding="UTF8"?> <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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--关联数据库配置文件--> <context:property-placeholder location="classpath:db.properties"/> <!--数据池 c3p0:自动化 dbcp:半自动化 druid:--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc_driver}"/> <property name="jdbcUrl" value="${jdbc_url}"/> <property name="user" value="${jdbc_user"/> <property name="password" value="${jdbc_password}"/> </bean> <!--配置sqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!--绑定mybatis-config.xml--> <property name="configLocation" value="classpath:mybatis-config.xml"/> <property name="mapperLocations" value="classpath:com/xiaojing/mapper/*.xml"/> </bean> <!--配置Mapper扫描包,将Mapper接口注入到Spring容器,就无需实现BookMapper接口来注入sqlSession,从而实现动态注入sqlSession--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> <property name="basePackage" value="com.xiaojing.mapper"/> </bean> </beans>
-
写spring-service.xml
<?xml version="1.0" encoding="UTF8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--自动扫描包内的注解--> <context:component-scan base-package="com.xiaojing.service"/> <!--将所有的业务类注册到Spring中--> <bean id="bookService" class="com.xiaojing.service.BookServiceImpl"/> <!--声明式事务--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> </beans>
-
写service层
接口
package com.xiaojing.service; import com.xiaojing.pojo.Book; import java.util.List; public interface BookService { int addBook(Book book); int deleteBookByid(int id); Book queryBookById(int id); int updateBook(Book book); List<Book> queryAllBook(); }
实现
package com.xiaojing.service; import com.xiaojing.mapper.BookMapper; import com.xiaojing.pojo.Book; import org.mybatis.spring.SqlSessionTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import java.util.List; public class BookServiceImpl implements BookService { private BookMapper mapper; @Autowired public void setMapper(BookMapper mapper) { this.mapper = mapper; } public int addBook(Book book) { return mapper.addBook(book); } public int deleteBookByid(int id) { return mapper.deleteBookByid(id); } public Book queryBookById(int id) { return mapper.queryBookById(id); } public int updateBook(Book book) { return mapper.updateBook(book); } public List<Book> queryAllBook() { return mapper.queryAllBook(); } }
5、Controller层——Spring MVC
-
配置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"> <!--注册DispatcherServlet--> <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:spring-mvc.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>encoding</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>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!--session设置--> <session-config> <session-timeout>15</session-timeout> </session-config> </web-app>
-
配置spring-mvc.xml
<?xml version="1.0" encoding="UTF8"?> <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 https://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"> <!--开启注解扫描--> <context:component-scan base-package="com.xiaojing.controller"/> <!--开启mvc注解支持--> <mvc:annotation-driven/> <!--视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="resolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> </beans>
6、业务操作
完整流程:
- 在mapper层写对应的操作数据库接口以及对应的sql语句
- 在service层调用mapper层接口,并增加需要的横切业务
- 在controller层调用service层接口,实现url到controller的映射
- 前端内容
1、书籍展示
-
controller
/*controller层调service层*/ @Controller @RequestMapping("/books") public class BooksController { private BooksService booksService; @Autowired public void setService(BooksService service) { this.booksService = service; } @RequestMapping("/all") public String showAllBooks(Model model){ List<Books> books = booksService.queryAll(); model.addAttribute("msg",books); return "allbook"; } }
-
allbook.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>书籍展示</title> <%--使用Bootstrap--%> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> <link href="http://cdn.static.runoob.com/libs/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"> <h3>书籍展示列表</h3> </div> </div> <div class="row"> <div class="col-md-4 column" style="margin-bottom: 20px;"> <a class="breadcrumb" href="/books/toadd?id=${list.size()}">添加书籍</a> </div> <div class="col-md-4 column" style="margin-bottom: 20px;float: right"> <form action="/books/search" method="get" class="form-inline"> <div class="form-group"> <input type="text" name="search" class="form-control" placeholder="请输入要查询的书籍" required="required"> <input type="submit" class="btn btn-default" style="float: right"> </div> </form> </div> </div> </div> <div class="row clearfix"> <div class="col-md-12 column"> <table class="table table-striped table-hover"> <thead> <tr> <td>书籍编号</td> <td>书籍名称</td> <td>书籍数量</td> <td>作者</td> <td>价格</td> <td>操作</td> </tr> </thead> <tbody> <c:forEach var="book" items="${list}" > <tr> <td>${book.id}</td> <td>${book.name}</td> <td>${book.count}</td> <td>${book.author}</td> <td>${book.price}</td> <td> <a href="${pageContext.request.contextPath}/books/toupdate?id=${book.id}">修改</a> | <a href="${pageContext.request.contextPath}/books/delete?id=${book.id}">删除</a> </td> </tr> </c:forEach> </tbody> </table> </div> </div> </div> </body> </html>
2、书籍增添
-
controller
/*添加书籍*/ @RequestMapping("/toadd") public String toAddPage(int id,Model model){ model.addAttribute("id",id+1); return "addbook"; } @RequestMapping("/add") public String addBooks(Books books){ System.out.println("add======>book:"+books); booksService.addBook(books); return "redirect:/books/all"; //重定向@RequestMapping("/all")请求 }
-
addbook.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>书籍添加</title> <%--使用Bootstrap--%> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> <link href="http://cdn.static.runoob.com/libs/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"> <h3>书籍添加</h3> </div> </div> </div> <form class="form-horizontal" style="width: 20%;" action="/books/add" method="get"> <input type="hidden" name="id" value="${id}"> <div class="form-group"> <label for="bookName">书籍名称</label> <input type="text" class="form-control" id="bookName" name="name" required> </div> <div class="form-group"> <label for="bookCount">书籍数量</label> <input type="text" class="form-control" id="bookCount" name="count" required> </div> <div class="form-group"> <label for="bookAuthor">作者</label> <input type="text" class="form-control" id="bookAuthor" name="author" required> </div> <div class="form-group"> <label for="bookPrice">价格</label> <input type="text" class="form-control" id="bookPrice" name="price" required> </div> <button type="submit" class="btn btn-default" style="float: right;">添加</button> </form> </div> </body> </html>
3、书籍更改
-
controller
/*修改书籍*/ @RequestMapping("/toupdate") public String toUpdate(int id,Model model){ Books books = booksService.queryBook(id); model.addAttribute("books",books); return "update"; } @RequestMapping("/update") public String updateBooks(Books books){ System.out.println("update=====>book:"+books); booksService.updateBook(books); return "redirect:/books/all"; }
-
update.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>书籍修改</title> <%--使用Bootstrap--%> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> <link href="http://cdn.static.runoob.com/libs/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"> <h3>书籍修改</h3> </div> </div> </div> <form class="form-horizontal" style="width: 20%;" action="/books/update" method="get"> <%--update失败分析:开始以为是事务没有提交,后配置事务仍然失败;查看执行的sql,sqk执行失败,发现传回数据库时,没有id--%> <input type="hidden" name="id" value="${books.id}"> <div class="form-group"> <label for="bookName">书籍名称</label> <input type="text" class="form-control" id="bookName" name="name" value="${books.name}" required> </div> <div class="form-group"> <label for="bookCount">书籍数量</label> <input type="text" class="form-control" id="bookCount" name="count" value="${books.count}" required> </div> <div class="form-group"> <label for="bookAuthor">作者</label> <input type="text" class="form-control" id="bookAuthor" name="author" value="${books.author}" required> </div> <div class="form-group"> <label for="bookPrice">价格</label> <input type="text" class="form-control" id="bookPrice" name="price" value="${books.price}" required> </div> <button type="submit" class="btn btn-default" style="float: right;">保存</button> </form> </div> </body> </html>
4、书籍删除
controller
@RequestMapping("/delete")
public String deleteBooks(int id){
System.out.println("delete=====>book:"+id);
booksService.deleteBook(id);
int i = booksService.updateById(id);
System.out.println("update=====>book:"+i);
return "redirect:/books/all";
}
注意:在书籍删除的时候,需要更新书籍的id信息
updateById
int updateById(int id);
<update id="updateById">
update ssm_book.book set `id`=`id`-1 where `id`>#{id}
</update>
5、搜索功能
-
mapper接口及Mapper.xml
List<Books> searchBook(String name);
<select id="searchBook" parameterType="String" resultType="books"> select * from ssm_book.book where `name` like "%"#{name}"%" </select>
-
service
public List<Books> searchBook(String name) { return mapper.searchBook(name); }
-
controller
@RequestMapping("/search") public String searchBooks(String search,Model model){ System.out.println("searchName=====>"+search); List<Books> books = booksService.searchBook(search); model.addAttribute("searchList",books); return "search"; }
注意:模糊查询的时候,记住一定要加通配符!
BUG记录
Error creating bean with name 'sqlSessionFactory' defined in class path resource [spring-mapper.xml]
经过反复对比和查看,发现错误出在mybatis-config.xml和spring-mapper.xml中,如果在mybatis-config.xml注册了mapper,那么在spring-mapper.xml中就不能绑定注册文件,即
<!--设置sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--绑定mybatis-config.xml-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!--绑定注册文件-->
<!--<property name="mapperLocations" value="classpath:com/xiaojing/mapper/*.xml"/>-->
</bean>
我想,二者映射重复注册了,导致无法生成sqlSessionFactory
-
Error creating bean with name 'mvcContentNegotiationManager'
测试的时候报错,发现没有导入servlet的依赖,导入后解决
-
开启服务器后,发现空指针问题,但经过Junit测试,是可以从service层调出数据的,所以一定是配置spring的时候出的问题。最终发现:
-
乱码问题
-
第一步,配置xml
<!--注册Spring的编码过滤器--> <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> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <!--注意点:‘/’和‘/*’的区别,‘/’过滤访问的所有请求,但不过滤对.jsp的访问;'/*'过滤根目录下的所有访问请求--> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
还是出现乱码,配置tomcat的server.xml
问题解决!
-